Skip to main content

Error Handling

HttpException

Throw from anywhere in the pipeline; the framework maps it to a response:

app.get("/users/{id}", ctx -> {
User user = repo.find(ctx.pathParamAsLong("id"))
.orElseThrow(() -> new NotFoundException("No such user"));
ctx.json(user);
});

Built-in subclasses: BadRequestException (400), UnauthorizedException (401), ForbiddenException (403), NotFoundException (404), MethodNotAllowedException (405), PayloadTooLargeException (413), TooManyRequestsException (429) — or new HttpException(status, message) for anything else.

Default rendering is a uniform JSON body:

{"status": 404, "error": "No such user"}

Custom exception handlers

Map your own exception types (subclasses match too):

app.exception(SQLException.class, (e, ctx) ->
ctx.status(503).json(Map.of("error", "database unavailable")));

Custom status pages

app.error(404, ctx -> ctx.html("<h1>Lost?</h1>"));
app.error(405, ctx -> ctx.json(Map.of("error", "wrong method")));

Unexpected exceptions

Anything not mapped becomes an opaque 500: the message and stack trace go to the log, never to the client. If an exception handler itself fails, a plain 500 is emitted and both failures are logged.

Validation errors

ctx.bodyValidator(...) throws ValidationException (a 400) carrying all failed checks:

{"status": 400, "error": "Validation failed: name is required; age must be positive"}

Annotation-based validation (ligero-validation)

Prefer standard constraints on a record? The optional ligero-validation module wraps Jakarta Bean Validation (Hibernate Validator):

record NewUser(@NotBlank String name, @Email String email, @Min(18) int age) {}

app.post("/users", ctx -> {
NewUser user = Validate.orThrow(ctx.body(NewUser.class)); // 400 with every violation
ctx.status(201).json(service.create(user));
});

Validate.orThrow(bean) returns the bean or throws a 400 listing every field: message; Validate.errors(bean) is the non-throwing form. It's opt-in (Bean Validation uses reflection); ctx.bodyValidator(...) stays for reflection-free checks.