Skip to content

Error Handling

Policy in practice

Each handler is wrapped in a try { … } catch (error) { … } block. The catch typically:

  1. Logs the error to stdout: console.log("error", error) (no structured fields)
  2. Returns a JSON envelope: { status: false, data: null, code: 500, message: "Something Went Wrong!" }

The default envelope is initialised at the top of the handler and overwritten on success. This means a handler that crashes before reaching its try block will still return the default envelope as long as Express's default error handler is reached — but in practice, an uncaught throw in an async handler will cause Express to send a stack trace or hang the response (since async errors don't auto-propagate to Express's default handler without next(err)).

Anti-patterns observed

  • No next(err) propagation. Handlers don't pass errors to Express's error middleware (because there is no error middleware registered). Every handler must catch its own errors or risk an unhandled rejection.
  • No retry logic for transient failures (DB connection drop, OpenAI/Bedrock 429s). A 500 is returned to the user, who has to retry by hand.
  • No correlation id in the error log → hard to match a user's report to a specific server-side log line.
  • "Something Went Wrong!" is the default error message returned to the FE. This is fine for end users but useless for debugging. The FE has no way to differentiate "your input was bad" from "the DB is down".
  • getErrorResponse(...) helper exists in helper/helper.js (from someli-api lineage) but not all handlers use it; some hand-build the envelope.

What works

  • The fact that every handler catches and returns a JSON 500 (rather than crashing the process) is good — the service is unlikely to be killed by user input.
  • The envelope is consistent enough that FE error handling is simple (if (response.status === false) showToast(response.message)).

Recommendations (light touch)

  1. Add a single Express error middleware that catches anything not handled per-handler:
    app.use((err, req, res, next) => {
      console.error("[unhandled]", err);
      res.status(500).json({ status: false, data: null, code: 500, message: "Something Went Wrong!" });
    });
    
  2. Standardise on getErrorResponse(...) and getSuccessResponse(...) in every handler — kill the hand-built envelopes.
  3. Add a request id middleware and include it in error responses so users can quote it back when they report bugs.
  4. Differentiate 4xx from 5xx:
  5. Bad input → 400, { status: false, message: "<reason>" }
  6. Auth failure → 401 (already done by middlewares/auth.js)
  7. Not found → 404, { status: false, message: "Not found" }
  8. Server failure → 500
  9. Use express-validator (already a dep) consistently for input validation. Today it's used only in middlewares/validation.js for one or two endpoints.

What's downstream of an error

When an error occurs:

  1. Logged to stdout (PM2 captures)
  2. JSON envelope returned to FE
  3. FE shows a generic toast via toast({ title: "Error", description: error.message }) (per admin_console_R/src/services/api.ts)
  4. (No incident pipeline; no Sentry; no PagerDuty.)