Error Handling
Introduction
JCC Express MVC registers HTTP error handling after routes are built (jcc-express-mvc/lib/Server/index.ts → httpErrors). Two pieces from AppErrorHandler matter in order:
errorRoutesHandler— a normal Express handler for requests that never matched a route (404).handler— Express’s four-argument error middleware(err, req, res, next), which receives failures passed tonext(error)or thrown from async code that the router wraps.
Route actions are executed inside asyncHandler and a try / catch so rejected promises and synchronous throws from controller code are forwarded to that error middleware (jcc-express-mvc/lib/Routes/RouteBuilder.ts, jcc-express-mvc/lib/util/index.ts).
404 — no matching route
When no route matches the request, the stack falls through to AppErrorHandler.errorRoutesHandler, which responds with pageNotFound.html from the framework’s Error/public assets at status 404.
Application error middleware (AppErrorHandler.handler)
The handler inspects err in a fixed order (jcc-express-mvc/lib/Error/AppErrorHandler.ts).
AuthorizationException
Thrown when a FormRequest subclass’s authorize() returns true (meaning “not allowed” in this framework’s convention). Response:
- If
req.expectsJson()and the request is not Inertia: 403 JSON{ message }. - Otherwise: flash key
errorwith message"Forbidden", status 403,redirectBack()(seeResponse.md).
Validation failures (ValidationException or err.type === VALIDATION_ERROR)
Covers ValidationException from Validator.validate and any error object whose type equals the VALIDATION_ERROR constant (jcc-express-mvc/lib/Error/Constants/error.ts).
- JSON (expects JSON, not Inertia): 422 with
{ errors: err.message }. OnValidationException,err.messageis actually the flattened field → message map built inValidationException-v2(first message per field). - Web: 422
redirectBack(). If the error is aValidationExceptionwitherrors,VALIDATION_ERRORis flashed again for templates (validation already flashes inValidator.validate; the handler may duplicate that flash).
Details of validation and flashes are in Validation.md, Request.md, and Session.md.
Blade / view engine errors (DEFAULT_ENGINE_ERROR)
Errors tagged with err.type === DEFAULT_ENGINE_ERROR return 500 JSON { errors: err.message }.
Everything else (generic server errors)
Non-matching errors go through stack parsing and APP_DEBUG:
APP_DEBUG"true"(string from config):DisplayError.showrenders an HTML page with a source snippet around the reported file/line, or 500 JSON withstackanderrorwhen the client expects JSON (jcc-express-mvc/lib/Error/DisplayErrorCode.ts).- Otherwise: 500 static
500.htmlfrom the frameworkError/publicfolder.
Propagating errors from your code
The framework is built with a controller-based architecture similar to Laravel. Rejections and synchronous throws from controller actions are already wired through asyncHandler and the inner catch in registerRoute, so in most cases a simple throw or an await on a failing promise is enough — the error reaches AppErrorHandler without extra boilerplate.
If you prefer explicit control, use try / catch and forward with next(error):
Calling next(error) skips the remaining middleware stack and jumps straight to the error middleware where AppErrorHandler takes over.
Middleware — The same pattern applies: call next(err) with an Error (or subclass) to forward the failure.
Manual JSON errors — For full control over the response, you can return res.status(n).json(...) directly inside a route and never call next.
Helper types and exceptions
AppError (jcc-express-mvc/lib/Error/AppError.ts) — Error subclass with optional type and cause; useful when you want a stable err.type for future branching (today AppErrorHandler only treats VALIDATION_ERROR and DEFAULT_ENGINE_ERROR by type, not AppError specifically).
Other exported errors (for example SocialiteAuthError, MissMatchTokenException) follow normal Error handling unless you map them in custom middleware or extend AppErrorHandler.
Constants under jcc-express-mvc/lib/Error/Constants/error.ts are mostly internal labels for subsystems; the global HTTP behavior above is driven by AppErrorHandler plus VALIDATION_ERROR / DEFAULT_ENGINE_ERROR.
Process-level rejections
unhandledRejection on the process is logged in Server.server; it does not automatically send an HTTP response. Prefer handling failures inside the request pipeline so clients get a proper status and body.
Summary
- 404 — unmatched routes → framework
pageNotFound.html. - 403 —
AuthorizationException→ JSON or flash +redirectBack. - 422 — validation-style errors → JSON
errorsorredirectBackwith flashes. - 500 — debug HTML/JSON snippet when
APP_DEBUGis on, otherwise500.html. - Forward errors with
next(err)in middleware; routethrow/ async failures are already passed tonextby the route wrapper.
