Troubleshooting
The errors people meet most often with RiserBob, what causes them and how to fix them.
Find your symptom, read the cause, apply the fix. Most problems come from a handful of habits, and every one of them is visible in the server log.
A request returns 500
Handler did not send a response
The handler finished without returning a Response. The most common cause is a generated controller whose body is still a TODO, or a missing return.
// Wrong: the Response is created and thrown awayreadonly findAll: SpongHandler = async (spongReq, spongRes) => { spongRes.SpongOK({ success: true });}; // Rightreadonly findAll: SpongHandler = async (spongReq, spongRes) => { return spongRes.SpongOK({ success: true });};Status 204 cannot have a response body
json() refuses a body for 204, 205 and 304. Use SpongNoContent() for an empty success, or answer 200 with a message.
A database error with an unreadable message
Any error that is not an HttpError becomes Internal Server Error for the client on purpose. Read the real error in the server log. When the cause is a bad id, validate it first. See Error handling.
A request returns 4xx
| Symptom | Cause | Fix |
|---|---|---|
401 on every protected route of a new module | The generated verifyToken returns null. | Implement verifyToken, or remove the auth middleware from a public route. |
401 although you are logged in | The middleware reads a different source than you send. The mode may be 'cookie' while the client sends a header, or the cookie name differs. | Match mode and cookieName to what the client sends. See Authentication. |
401 with a header in 'both' mode | A request with an Authorization header is judged by the header alone. A value that is not Bearer <token> is rejected and the cookie is not tried. | Send a valid Bearer header, or do not send the header. |
405 Method Not Allowed | The path exists, but not for that method. The Allow header lists the valid ones. | Use a listed method, or register the method you need. |
404 Not Found for a route that exists | A different path, a different method, or the route was never registered. The server log prints the method and the path it received. | Compare the log with your registration. Make sure the module is registered in src/index.ts. |
415 Unsupported Media Type | json() needs Content-Type: application/json. | Send the header, for example curl -H "Content-Type: application/json". |
400 Invalid JSON body | The body is not valid JSON. A trailing comma or single quotes are the usual cause. | Validate the JSON before sending it. |
413 Content Too Large | The request is bigger than 10 MiB. | Send less data, or upload large files straight to a storage service. |
The server fails to start
| Message | Cause | Fix |
|---|---|---|
must start with "/" | A route path has no leading slash. | Write /users, not users. |
Route "GET /x" already lives in Bikini Bottom | The same method and path were registered twice. | Remove the duplicate. Two modules may be declaring the same path. |
CORS cannot use "*" with credentials enabled | corsMiddleware was created with origin: '*' and credentials: true. | List the allowed origins explicitly. |
Unknown validation rule or required and nullable cannot be combined | A rule file has a typo, or a field uses both rules. | Fix the schema. The error is thrown the first time that schema is used. |
DATABASE_URL is missing | The .env file is missing, or it is not in the project root. | Create .env next to package.json and restart the server. |
Middleware does not run
Global middleware is ignored
Global middleware is attached when a route is registered, so spongUse only affects the routes registered after it.
// Wrong: the route is registered firstbob.spongGet("/", handler);bob.spongUse(loggerMiddleware); // Rightbob.spongUse(loggerMiddleware);bob.spongGet("/", handler);next() called multiple times
A middleware called spongNext() twice. Call it once and return its result, for example return spongNext().
The admin middleware always answers 401
It reads spongReq.user, which AuthMiddleware sets. Pass the auth middleware first and the admin middleware second.
Cookies and CORS
| Symptom | Cause | Fix |
|---|---|---|
| The browser never stores the cookie | The cookie was set, but applyTo was not called on the response you returned. | Return cookies.applyTo(response). |
The cookie is missing on http://localhost | Secure cookies are the default, and some browsers refuse them over plain HTTP. | Create the manager with defaults: { secure: false } in development. |
| Logout does not log you out | The deleted cookie was not applied, or path, domain or sameSite differ from the original. | Call applyTo and pass the same attributes you used in set. |
| The browser reports a CORS error | The request origin is not in origin, or the front end does not send credentials. | Add the exact origin, and use fetch(url, { credentials: 'include' }). |
| The cookie is sent, but the user is not found | AuthMiddleware reads the cookie with a plain get. | Do not use setSigned for the token cookie, or verify the signature in your verifier. |
TypeScript
| Message | Cause | Fix |
|---|---|---|
Type 'string | undefined' is not assignable to type 'string' on params.id | noUncheckedIndexedAccess is on. A route parameter might be missing. | Check it first: if (!id) return spongRes.SpongBadRequest(). |
Not all code paths return a value in a handler | A branch ends without a return. | Return a Response on every path. |
'X' is a type and must be imported using a type-only import | verbatimModuleSyntax is on. | Write import type { SpongHandler } from "riser-bob". |
A property is missing on spongReq.user | The user has an id and whatever your verifier returned. Other fields have the type unknown. | Return the fields you need from the verifier, and narrow them before use. |
Still stuck
Read the server log first: RiserBob prints what it received and why it answered as it did. If it still looks like a framework bug, open an Issue with the steps to reproduce. See Contributing.