Skip to main content

Error Handling

Balda.js provides intelligent error handling out of the box, following HTTP specifications (RFC 7231) for proper status codes and security best practices for error responses.

Error Response Format

All error responses follow a standardized format:

// Development (NODE_ENV !== 'production')
{
"code": "ROUTE_NOT_FOUND",
"message": "ROUTE_NOT_FOUND: Cannot GET /unknown",
"stack": "Error: ROUTE_NOT_FOUND...",
"cause": undefined
}

// Production (NODE_ENV === 'production')
{
"code": "ROUTE_NOT_FOUND",
"message": "ROUTE_NOT_FOUND: Cannot GET /unknown"
}

Why Stack Traces Are Hidden in Production

Stack traces can expose sensitive information:

  • Internal file paths: /home/app/src/server/server.ts
  • Code structure: Function names and middleware chains
  • Framework internals: How your application processes requests

This information could help attackers understand your application structure and find vulnerabilities.

404 Not Found

When a request is made to a path that doesn't exist for any HTTP method, Balda.js returns a 404 Not Found response.

// No routes defined for /unknown
// Request: GET /unknown
// Response: 404 Not Found

{
"code": "RouteNotFoundError",
"message": "ROUTE_NOT_FOUND: Cannot GET /unknown"
}

Custom Not Found Handler

You can customize the 404 response using setNotFoundHandler:

import { Server } from 'balda-js';

const server = new Server({ port: 3000 });

server.setNotFoundHandler((req, res) => {
res.status(404).json({
error: 'Page not found',
path: new URL(req.url).pathname,
suggestion: 'Check the API documentation at /docs'
});
});

server.listen();

405 Method Not Allowed

When a request is made to a path that exists but with a different HTTP method, Balda.js returns a 405 Method Not Allowed response with an Allow header listing the valid methods.

import { Server } from 'balda-js';

const server = new Server({ port: 3000 });

// Only POST is allowed for /users
server.post('/users', (req, res) => {
res.created({ id: 1, ...req.body });
});

server.listen();
# Request: GET /users
# Response: 405 Method Not Allowed
# Headers: Allow: POST

{
"code": "MethodNotAllowedError",
"message": "METHOD_NOT_ALLOWED: Cannot GET /users"
}

Multiple Allowed Methods

If a path is registered with multiple methods, all valid methods are listed in the Allow header:

server.get('/users', (req, res) => {
res.json({ users: [] });
});

server.post('/users', (req, res) => {
res.created(req.body);
});

// Request: DELETE /users
// Response: 405 Method Not Allowed
// Headers: Allow: GET, POST

Route Matching Priority

Balda.js uses a radix trie router with the following matching priority:

PriorityTypeExampleDescription
1stStatic/usersExact path match
2ndParameterized/users/:idDynamic segments
3rdWildcard*Catch-all (404/405 handler)

This ensures that specific routes always take precedence over catch-all handlers.

server.get('/users', handler);        // Matches GET /users
server.get('/users/:id', handler); // Matches GET /users/123
// Wildcard catch-all handles everything else (404/405)

Global Error Handler

For handling errors thrown during request processing, use setErrorHandler:

import { Server } from 'balda-js';

const server = new Server({ port: 3000 });

server.setErrorHandler((req, res, next, error) => {
console.error('Request error:', error);

// Handle specific error types
if (error.name === 'ValidationError') {
return res.badRequest({
code: 'VALIDATION_ERROR',
message: error.message
});
}

if (error.name === 'UnauthorizedError') {
return res.unauthorized({
code: 'UNAUTHORIZED',
message: 'Authentication required'
});
}

// Default error response
res.internalServerError({
code: 'INTERNAL_ERROR',
message: 'An unexpected error occurred'
});
});

server.listen();

Built-in Error Types

Balda.js provides several built-in error types:

ErrorStatusDescription
RouteNotFoundError404Path doesn't exist for any method
MethodNotAllowedError405Path exists but not for requested method
JsonNotValidError400Invalid JSON in request body
FileTooLargeError413Uploaded file exceeds size limit

Best Practices

1. Always Set NODE_ENV in Production

NODE_ENV=production node server.js

This ensures stack traces are never exposed to clients.

2. Use Specific Error Handlers

server.setErrorHandler((req, res, next, error) => {
// Log the full error internally
console.error({
error: error.message,
stack: error.stack,
path: req.url,
method: req.method
});

// Return safe response to client
res.internalServerError({
code: 'INTERNAL_ERROR',
message: 'Something went wrong'
});
});

3. Provide Helpful 404 Responses

server.setNotFoundHandler((req, res) => {
const pathname = new URL(req.url).pathname;

res.status(404).json({
code: 'NOT_FOUND',
message: `The endpoint ${pathname} does not exist`,
docs: '/api/docs'
});
});

4. Log Errors for Debugging

server.setErrorHandler((req, res, next, error) => {
// Use your logging service
logger.error({
requestId: req.id,
error: error.message,
stack: error.stack,
url: req.url,
method: req.method
});

res.internalServerError({
code: 'INTERNAL_ERROR',
requestId: req.id // Include for support reference
});
});

HTTP Status Code Reference

StatusMethodDescription
res.badRequest()400Invalid request syntax
res.unauthorized()401Authentication required
res.forbidden()403Access denied
res.notFound()404Resource not found
res.methodNotAllowed()405HTTP method not supported
res.conflict()409Resource conflict
res.internalServerError()500Server error