# Das Fehlerformat

Jeder Fehler der API kommt in demselben Rumpf zurück: `code`, `message` und `traceId` immer, weitere Felder nach Lage. Diese Seite nennt die Felder, die Regel, nach der aus einem Code der HTTP-Status wird, die sieben zentralen Antworten der Referenz und die RFC-9457-Form.

> **Typ:** nachschlagen
> **Für wen:** Wer Fehlerantworten in einem Client auswertet oder eine Antwort bei einer Rückfrage beschreiben muss.
> **Voraussetzung:** keine — das Format gilt auf jeder Route, auch ohne Anmeldung

## Der Fehlerrumpf

```json
{
  "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 }
}
```

| Feld | Wann | Inhalt |
|---|---|---|
| `code` | immer | der stabile Fehlercode in der Form `Bereich.Ursache`, Muster `^[A-Z][a-zA-Z]+\.[A-Z][a-zA-Z0-9]+$` |
| `message` | immer | Kurzbeschreibung für Menschen, 1–1000 Zeichen, kann sich ändern |
| `traceId` | immer | die Spur dieses Aufrufs: `trc_` und 26 Zeichen, nie leer und identisch mit der Kopfzeile `X-Trace-Id` |
| `details` | nach Lage | Zusatzangaben ohne personenbezogene Daten: `issues` bei Eingabefehlern, `expectedVersion` und `actualVersion` bei Versionskonflikten. Fehlt ganz, wenn es nichts gibt |
| `correlationId` | nach Lage | Kennung eines zusammenhängenden Vorgangs, `cor_…`, bis 128 Zeichen |
| `retryAfterSeconds` | bei nachgelagerten Diensten | ganze Sekunden bis zum nächsten Versuch. Geht zusätzlich als Kopfzeile `Retry-After` hinaus |
| `externalService` | bei nachgelagerten Diensten | Name des Dienstes, der nicht verwertbar geantwortet hat |
| `stack` | nie im Produktivbetrieb | nur in Entwicklungsumgebungen bei Serverfehlern |

Zwei Regeln für jeden Client: Schalten Sie auf `code`, nie auf `message`. Und nennen Sie bei Rückfragen die `traceId` — sie ist der Schlüssel, mit dem der Betrieb den Aufruf wiederfindet.

## Wie aus dem Code der HTTP-Status wird

Der Status ist nicht frei gesetzt, sondern deterministisch aus dem Code abgeleitet. Die Auflösung prüft in fester Reihenfolge, und der erste Treffer gewinnt.

| Stufe | Regel | Beispiel |
|---|---|---|
| 1 | Exakte Zuordnung des einzelnen Codes | `Validation.IdempotencyKeyRequired` → 409, `Http.BadRequest` → 400 |
| 2 | Zuordnung des Fachbereichs | `Billing.LicensesExhausted` → 402, `Tenant.Frozen` → 403, `Signup.TicketInvalid` → 401 |
| 3 | Konvention des Namensraums | `Validation.*` → 422, `Auth.*` → 401, `Permission.*` → 403, `*.NotFound` → 404, `Conflict.*` → 409, `RateLimit.*` → 429, `Payload.*` → 413, `Integration.*` → 502 |
| 4 | Sonst | 500 |

Deshalb tragen die meisten Serverfehler keine eigene Zuordnung: Sie fallen bewusst auf 500 durch. Wo ein Fachcode von der Konvention abweicht, ist das Absicht und auf der jeweiligen Code-Seite begründet.

## Die sieben zentralen Antworten

Die Referenz beschreibt sieben Antworten zentral. Sie bedeuten auf jeder Operation dasselbe.

| Antwort | Status | Bedeutung |
|---|---|---|
| `Unauthorized` | 401 | nicht oder ungültig angemeldet |
| `PermissionDenied` | 403 | angemeldet, aber ohne das nötige Recht |
| `NotFound` | 404 | die Ressource existiert nicht oder ist für Sie nicht sichtbar |
| `Conflict` | 409 | gleichzeitige Änderung oder Verstoß gegen eine Eindeutigkeit |
| `ValidationFailed` | 422 | die Anfrage verletzt das Schema oder eine fachliche Regel |
| `RateLimit` | 429 | zu viele Anfragen, `Retry-After` nennt die Wartezeit |
| `IntegrationError` | 502 | ein nachgelagerter Dienst antwortete nicht verwertbar |

## RFC 9457: Problem Details

Senden Sie `Accept: application/problem+json`, antwortet die API mit `Content-Type: application/problem+json` und einem `ProblemDetails`-Dokument statt des Standardrumpfs.

| Feld | Wann | Inhalt |
|---|---|---|
| `type` | immer | die Adressform des Codes |
| `title` | immer | Kurztitel, bis 200 Zeichen |
| `status` | immer | der HTTP-Status als Zahl |
| `detail` | immer | die Beschreibung, bis 1000 Zeichen |
| `code` | immer gesetzt | derselbe Fehlercode wie im Standardrumpf |
| `instance` | nach Lage | der angefragte Pfad |
| `errorDetails` | nach Lage | dieselben Zusatzangaben wie `details` |
| `traceId`, `correlationId`, `retryAfterSeconds` | nach Lage | wie im Standardrumpf |

Einen `stack` gibt es in dieser Form nicht.

```bash
curl -sS "$SZENERA_API/v1/scenes/scn_00000000000000000000000000" \
  -H "Authorization: Bearer $SZENERA_API_KEY" \
  -H "Accept: application/problem+json"
```

## Wo die Codes stehen

Der Katalog umfasst 612 Codes, verteilt auf sieben Seiten:

| Seite | Bereiche |
|---|---|
| [Auf jeder Route möglich](/de/api/error-codes-general) | Anmeldung, Rechte, Eingabeprüfung, Konflikte, Drosselung, Nutzlast, HTTP, Betreiberrouten |
| [Konten und Sitzungen](/de/api/error-codes-accounts) | Konten, Schlüssel, Geräte, Anmeldung, zweiter Faktor |
| [Organisation, Zugang, Beitritt](/de/api/error-codes-organization) | Stammdaten, Rollen, Einladungen, Registrierung, Speicher-Verbindungen |
| [Abrechnung](/de/api/error-codes-billing) | Paket, Lizenzen, Zahlungsmittel, Rechnungen |
| [Medien, Szenen, Programme, Apps](/de/api/error-codes-content) | Medien, Szenen, Playlisten, Programme, App-Katalog, Marktplatz, App-Laufzeit, Nachrichten-Quellen, Werbung |
| [Geräte, Wiedergabe, Meldungen, Betrieb](/de/api/error-codes-devices-operations) | Flotte, Wiedergabe, Echtzeit, Webhooks, Auswertung, Prüfprotokoll, Betriebskonsole |
| [Serverfehler (5xx)](/de/api/error-codes-server) | Invarianten, Start, Datenbank, nachgelagerte Dienste |

## Weiterführendes

- [Fehlercodes: auf jeder Route möglich](/de/api/error-codes-general)
- [Was eine Antwort enthält](/de/getting-started/response-contents)
- [Gleichzeitige Änderungen: ETag und If-Match](/de/api/etag-and-if-match)
