Default Error Behavior
This error handling mechanism catches every error that occurs during server runtime, which covers route handler errors, middleware failures, route not found scenarios, static file errors, and any other uncaught exception during request processing. Without a custom error handler set through router.catch(), Deserve falls back to this default behavior so the server never crashes from unhandled errors. The same fallback applies when a custom handler runs but returns something other than a Response, so the default handler always produces the final reply.

Basic Default Behavior
Without a call to router.catch(), Deserve handles every error with a default response, JSON or HTML, and the matching status code:
import { Router } from '@neabyte/deserve'
const router = new Router({
routes: { directory: './routes' }
})
// No router.catch, defaults take over
await router.serve(8000)Default Error Response
The default error response (without custom router.catch()) follows the client's Accept header:
- Accept includes
application/jsonorapplication/problem+json→ a problem-details body{ type, title, status, instance }sent asapplication/problem+json - Otherwise → HTML body: simple error page with status and message (escaped)
Also:
- Status Code: Preserves the original error status code (404, 500, etc.)
- Headers: Includes headers set via
ctx.set.header()before the error
// Example default response (client requests JSON)
// Status: 404
// Content-Type: application/problem+json
// Body: { "type": "about:blank", "title": "Not Found", "status": 404, "instance": "/api/foo" }
// Example default response (client does not request JSON)
// Status: 404
// Body: HTML with <title>404</title> and error messageThe problem-details shape follows RFC 9457, where type is a problem URI, title is a short summary, status repeats the code, and instance carries the request path. A custom router.catch() replaces this body with whatever shape suits the client, covered in Error Object Details.
Error Scenarios
Default error handling covers all error types that can occur during request processing:
404 - Route Not Found
When no route matches the request path at all:
// GET /nonexistent
// Status: 404
// Body: JSON or HTML (by Accept header)
// Headers: {}This includes:
- Non-existent routes
- Paths that match no pattern during routing resolution
405 - Method Not Allowed
When the path matches a route but the method has no handler, the response is 405 with an Allow header listing the supported methods:
// DELETE /users (only GET and POST defined)
// Status: 405
// Body: JSON or HTML (by Accept header)
// Headers: { Allow: "GET, HEAD, POST" }HEAD is added automatically whenever a GET handler exists.
422 - Validation Failed
When a validation contract rejects request input, the default response is a plain problem-details body with the 422 status:
// POST /users with an invalid body
// Status: 422
// Content-Type: application/problem+json
// Body: { "type": "about:blank", "title": "Unprocessable Entity",
// "status": 422, "instance": "/users" }The default body never lists the failure reasons. Those reasons ride on error.error.cause as a string array, so a custom router.catch() reads them to build a field-level response. How a contract produces those reasons lives in Reading Validated Data.
500 - Server Errors
When a route handler throws any error or exception:
export function GET(ctx: Context): Response {
// Throwing is caught by Deserve
throw new Error('Something went wrong')
// Default reply is 500 JSON or HTML
}This covers:
- Uncaught exceptions in route handlers
- Runtime errors (TypeError, ReferenceError, etc.)
- Async operation failures
- Any error thrown during handler execution
Middleware Errors
When middleware functions throw errors or fail:
// A throwing middleware is caught too
router.use(async (ctx, next) => {
throw new Error('Middleware failed')
// Default reply is 500 JSON or HTML
})All middleware errors are caught and handled by the default error handler.
Static File Errors
When serving static files encounters issues:
// Serve static files at /static
router.static(
'/static',
{
path: './public'
}
)
// Missing file (GET /static/missing.jpg):
// Status 404, JSON or HTML per AcceptThis includes:
- File not found errors (404)
- File read permission errors (500)
- Filesystem operation failures (500)
- Invalid path resolution errors (500)
Request Processing Errors
Any unexpected errors during request handling:
// Errors in:
// - URL parsing
// - Context creation
// - Route matching
// - Response generation
// All default to: Status 500, JSON or HTML body (by Accept)Error Handling Guarantees
The default error handler ensures:
- No server crashes: All errors are caught and converted to HTTP responses
- Consistent behavior: Same error response format across all error types
- Header preservation: Headers set before the error are retained in the response
- Status code accuracy: Original error status codes (404, 500, etc.) are preserved