Error Handling

Robust error handling is essential for creating reliable and user-friendly APIs. Jetpath encourages centralizing error handling logic within your middleware, providing a consistent way to catch errors, log them, and send standardized responses to the client.


Philosophy

Instead of scattering try...catch blocks throughout your route handlers for common errors, Jetpath’s approach relies on:

  1. Signaling Errors: Using ctx.throw() or standard throw new Error() within route handlers or preceding middleware logic when something goes wrong.
  2. Centralized Catching: Intercepting these thrown errors within the post-handler function returned by your middleware.
  3. Standardized Responses: Formatting and sending consistent error responses from the middleware’s error handling block.

Throwing Errors

When you encounter a situation in your route handler (or pre-handler middleware logic) where processing cannot continue normally, you should signal an error. The preferred way is using ctx.throw().

Using ctx.throw()

The ctx.throw(codeOrData, message?) method is designed specifically for signaling HTTP-related errors. It sets the ctx.code (status code) and attaches an error message, then throws an error that interrupts the current execution flow.

Using throw new Error()

You can also use standard JavaScript throw new Error("Something broke"). This is suitable for unexpected internal errors. When caught by the middleware, ctx.code might not be set, so your middleware should typically default to a 500 Internal Server Error status code in these cases.

try {
  const result = await riskyOperation();
} catch (internalError) {
  console.error("Internal operation failed:", internalError);
  // Let the middleware handle formatting, just throw
  throw new Error("Internal processing error occurred.");
}

Handling Errors in Middleware

The post-handler function returned by your MIDDLEWARE_ definition is the primary location for catching and handling errors thrown from route handlers, validation logic (ctx.validate), or the pre-handler part of the middleware itself.

The err Parameter

This function receives the ctx object and an optional second argument, typically named err.

Middleware Error Handling Block

Here’s how to structure the error handling within your middleware’s returned function, based on the example in tests/app.jet.ts:

// Inside the function returned by MIDDLEWARE_
return (ctx, err?: Error) => {
  // =========================
  // === POST-HANDLER CODE ===
  // =========================
  const duration = Date.now() - startTime; // Assuming startTime from pre-handler
  ctx.set("X-Response-Time", `${duration}ms`);

// — Central Error Handling Logic — if (err) { // 1. Log the error (essential for debugging) // Use a proper logger plugin in production console.error({ message: Request Error: <span class="hljs-subst">${err.message}</span>, stack: err.stack, requestId: ctx.get("X-Request-ID"), // Include request context url: ctx.request.url, method: ctx.request.method, }); // Example with logger plugin: // ctx.plugins.logger?.error({ error: err.message, stack: err.stack, code: ctx.code, requestId: ctx.get("X-Request-ID") });

<span class="hljs-comment">// 2. Determine the Status Code</span>
<span class="hljs-comment">// Use ctx.code if it was set by ctx.throw() or before throwing.</span>
<span class="hljs-comment">// Default to 500 for unexpected errors (where ctx.code might still be 200 or unset).</span>
ctx.<span class="hljs-property">code</span> = ctx.<span class="hljs-property">code</span> &gt;= <span class="hljs-number">400</span> ? ctx.<span class="hljs-property">code</span> : <span class="hljs-number">500</span>;

<span class="hljs-comment">// 3. Format the Error Response Body</span>
<span class="hljs-comment">// Avoid leaking sensitive stack traces in production for 5xx errors!</span>
<span class="hljs-keyword">const</span> errorMessage = (ctx.<span class="hljs-property">code</span> &gt;= <span class="hljs-number">500</span> &amp;&amp; process.<span class="hljs-property">env</span>.<span class="hljs-property">NODE_ENV</span> === <span class="hljs-string">&#x27;production&#x27;</span>)
  ? <span class="hljs-string">&quot;Internal Server Error&quot;</span>
  : err.<span class="hljs-property">message</span> || <span class="hljs-string">&quot;An unexpected error occurred&quot;</span>;

<span class="hljs-keyword">const</span> errorResponse = {
  <span class="hljs-attr">error</span>: {
    <span class="hljs-attr">message</span>: errorMessage,
    <span class="hljs-attr">code</span>: ctx.<span class="hljs-property">code</span>,
    <span class="hljs-attr">requestId</span>: ctx.<span class="hljs-title function_">get</span>(<span class="hljs-string">&quot;X-Request-ID&quot;</span>), <span class="hljs-comment">// Helpful for tracing</span>
    <span class="hljs-comment">// Optionally include validation details for 400 errors if safe</span>
    <span class="hljs-comment">// details: (ctx.code === 400 &amp;&amp; err.details) ? err.details : undefined,</span>
  },
  <span class="hljs-attr">timestamp</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>().<span class="hljs-title function_">toISOString</span>(),
};

<span class="hljs-comment">// 4. Send the Error Response</span>
<span class="hljs-comment">// Ensure correct Content-Type (usually application/json)</span>
ctx.<span class="hljs-title function_">set</span>(<span class="hljs-string">&quot;Content-Type&quot;</span>, <span class="hljs-string">&quot;application/json&quot;</span>);
ctx.<span class="hljs-title function_">send</span>(errorResponse);

<span class="hljs-comment">// 5. IMPORTANT: Stop further processing</span>
<span class="hljs-comment">// Prevent subsequent logic (like 404 checks) from running</span>
<span class="hljs-keyword">return</span>;

} // — End of Error Handling —

// … Handle successful responses or 404s if no error occurred … // (As shown in the Middleware documentation page) };

[cite: Based on error handling logic in MIDDLEWARE_ in tests/app.jet.ts]


Specific Error Examples


Best Practices


Next Steps