You've deployed a Solon service and, at 2 a.m., a client starts sending malformed requests. Your endpoint answers with 400 Bad Request. A few minutes later someone calls a URL that doesn't exist — 404 Not Found. Then a colleague posts JSON to an endpoint that only accepts application/x-www-form-urlencoded — 415 Unsupported Media Type.
You grep your codebase for "Not Found" and "Unsupported Media Type" and find nothing. That's normal: you're not supposed to write those. Solon's built-in StatusException converts unhandled client-caused errors into HTTP status responses automatically. Knowing this exception hierarchy will save you a late night — and it's a neat look at how the framework thinks about failures.
The exception family tree
Solon's exceptions form two small trees. Everything framework-level descends from SolonException (provided by the solon module); the distributed world has its own root, CloudException (provided by solon.cloud):
SolonException (solon — the framework root)
└── StatusException (solon — client-caused errors, v2.8.3+)
├── AuthException (solon-security-auth)
├── ValidatorException (solon-security-validation)
└── CloudStatusException (solon-cloud)
CloudException (solon.cloud — the distributed root)
├── CloudConfigException (distributed config service)
├── CloudEventException (distributed event service)
├── CloudFileException (distributed file service)
└── CloudJobException (distributed job service)
StatusException: the one behind your 4xx
StatusException (available since v2.8.3) is a "status exception", and the official docs define its purpose precisely: it represents handling exceptions caused by the client side — as opposed to bugs or server-side failures. It carries a code (the HTTP status code) and a message (a description).
The key mechanism: when this exception is not handled, it is automatically converted into an HTTP status response. That's why a bare 404 pops out of your service even though you never wrote a line for it.
The framework itself throws it in four built-in places:
| When | What Solon throws |
|---|---|
| Multipart parsing fails | new StatusException("Bad Request", e, 400) |
| No route path record matches | new StatusException("Not Found", 404) |
| No route path method record matches | new StatusException("Method Not Allowed", 405) |
No Consumes match |
new StatusException("Unsupported Media Type", 415) |
So the four most common 4xx codes in a Solon app — 400, 404, 405, 415 — are all produced by this one class, from four well-defined routing/parsing checks. When you see one of them, don't hunt for where it's thrown in your code; check why the request didn't match instead.
Three derived exceptions
Three more exceptions extend StatusException, each from a different module, each with its own extra members:
| Exception | Module | What it signals | Extra members |
|---|---|---|---|
AuthException |
solon-security-auth |
Authentication/authorization failed |
code, status
|
ValidatorException |
solon-security-validation |
Parameter validation failed |
code, annotation, result
|
CloudStatusException |
solon-cloud |
A cloud component reported a status problem | code |
These are the "typed" versions you'll actually catch in business code: wrap a service call, catch AuthException, and you know the caller wasn't authenticated without inspecting the message text.
CloudException: the distributed family
When your app runs in distributed mode, errors from the cloud layer come from a separate root — CloudException, the base of the solon.cloud world:
| Exception | What it signals |
|---|---|
CloudConfigException |
Distributed config service error |
CloudEventException |
Distributed event service error |
CloudFileException |
Distributed file service error |
CloudJobException |
Distributed job service error |
If a Cloud*Exception shows up, the fault is almost always in the distributed component (config center, event bus, file store, job scheduler), not in your request handling — a useful first guess when triaging.
A mental model for debugging 4xx
Put together, the mapping is small enough to keep in your head:
-
400 / 404 / 405 / 415 → client-side problem; check the request format, path, HTTP method, and
Content-Typeagainst your route definitions (these are the four built-inStatusExceptionusages). -
AuthException→ authentication/authorization layer (solon-security-auth). -
ValidatorException→ parameter validation (solon-security-validation) — inspect theannotationandresultmembers for details. -
Cloud*Exception→ distributed component failure (solon.cloudfamily). -
Anything else extending
SolonException→ your own business exceptions; catch them where you'd normally handle domain errors.
Why the code matters
StatusException exists because, before v2.8.3, dealing with 400/404/405 required more manual work. Introducing a status-carrying exception (and auto-converting it to a response) gave the framework — and you — one consistent way to signal "the client got it wrong" all the way from routing internals to security/validation modules and cloud components. One pattern, one root, one mental model.
The full official description lives in the Solon docs — exception relationships (Solon v4.0.4).
Top comments (0)