The error format
The error body with code, message, and traceId, the RFC 9457 form, and the rule by which a code becomes the HTTP status.
4 minute readAPIUpdated: 10/25/2026
On this page
Before you start
- For
- Anyone who handles error responses in a client or has to describe a response when asking for help.
- Prerequisite
- none, because the format applies on every route, even without authentication
Every error of the API comes back in the same body: code, message, and traceId always, further fields if applicable. This page lists the fields, the rule by which a code becomes the HTTP status, the seven central responses of the reference, and the RFC 9457 form.
The error body
{
"code": "Conflict.OptimisticLock",
"message": "Die Szene „Willkommen & Öffnungszeiten\" wurde zwischenzeitlich geändert. Bitte neu laden und erneut speichern.",
"traceId": "trc_01KXZACQD0PFAD000000000001",
"correlationId": "cor_01KXZACQD0KETTE00000000001",
"details": { "sceneId": "scn_01KJPX8NH0SZENE00000000001", "expectedVersion": 3, "actualVersion": 4 }
}
| Field | When | Content |
|---|---|---|
code |
always | the stable error code in the form Area.Cause, pattern ^[A-Z][a-zA-Z]+\.[A-Z][a-zA-Z0-9]+$ |
message |
always | short description for humans, 1–1000 characters, may change |
traceId |
always | the trace of this call: trc_ and 26 characters, never empty and identical to the X-Trace-Id header |
details |
if applicable | additional information without personal data: issues for input errors, expectedVersion and actualVersion for version conflicts. Omitted entirely when there is nothing to report |
correlationId |
if applicable | identifier of a connected process, cor_…, up to 128 characters |
retryAfterSeconds |
for downstream services | whole seconds until the next attempt. Also sent as the Retry-After header |
externalService |
for downstream services | name of the service that returned an unusable response |
stack |
never in production | only in development environments, for server errors |
Two rules for every client: Branch on code, never on message. And include the traceId when you ask for help, because it is the key that lets the operations team find the call again.
How the HTTP status follows from the code
The status is not set freely but derived deterministically from the code. The resolution checks in a fixed order, and the first match wins.
| Step | Rule | Example |
|---|---|---|
| 1 | Exact mapping of the individual code | Validation.IdempotencyKeyRequired → 409, Http.BadRequest → 400 |
| 2 | Mapping of the functional area | Billing.LicensesExhausted → 402, Tenant.Frozen → 403, Signup.TicketInvalid → 401 |
| 3 | Convention of the namespace | Validation.* → 422, Auth.* → 401, Permission.* → 403, *.NotFound → 404, Conflict.* → 409, RateLimit.* → 429, Payload.* → 413, Integration.* → 502 |
| 4 | Otherwise | 500 |
That is why most server errors carry no mapping of their own: They deliberately fall through to 500. Where a domain code deviates from the convention, that is intentional and explained on the respective code page.
The seven central responses
The reference describes seven responses centrally. They mean the same on every operation.
| Response | Status | Meaning |
|---|---|---|
Unauthorized |
401 | missing or invalid authentication |
PermissionDenied |
403 | authenticated, but without the required permission |
NotFound |
404 | the resource does not exist or is not visible to you |
Conflict |
409 | concurrent change or violation of a uniqueness constraint |
ValidationFailed |
422 | the request violates the schema or a business rule |
RateLimit |
429 | too many requests, Retry-After gives the wait time |
IntegrationError |
502 | a downstream service returned an unusable response |
RFC 9457: Problem Details
If you send Accept: application/problem+json, the API responds with Content-Type: application/problem+json and a ProblemDetails document instead of the standard body.
| Field | When | Content |
|---|---|---|
type |
always | the address form of the code |
title |
always | short title, up to 200 characters |
status |
always | the HTTP status as a number |
detail |
always | the description, up to 1000 characters |
code |
always set | the same error code as in the standard body |
instance |
if applicable | the requested path |
errorDetails |
if applicable | the same additional information as details |
traceId, correlationId, retryAfterSeconds |
if applicable | as in the standard body |
There is no stack in this form.
curl -sS "$SZENERA_API/v1/scenes/scn_00000000000000000000000000" \
-H "Authorization: Bearer $SZENERA_API_KEY" \
-H "Accept: application/problem+json"
Where the codes are listed
The catalog contains 612 codes, spread across seven pages:
| Page | Areas |
|---|---|
| Possible on any route | authentication, permissions, input validation, conflicts, throttling, payload, HTTP, operator routes |
| Accounts and sessions | accounts, keys, devices, sign-in, second factor |
| Organization, access, joining | master data, roles, invitations, registration, storage connections |
| Billing | package, licenses, payment method, invoices |
| Media, scenes, programs, apps | media, scenes, playlists, programs, app catalog, marketplace, app runtime, news sources, advertising |
| Devices, playback, notifications, operations | fleet, playback, realtime, webhooks, analytics, audit log, operations console |
| Server errors (5xx) | invariants, startup, database, downstream services |