Kasimir Docs DEEN Zur App →

API: Fehler, Status-Codes & Limits

Vollständige Referenz der HTTP-Status-Codes, des OpenAI-kompatiblen Fehlerformats, der Budget- und Größenlimits der öffentlichen Kasimir-API.

Die öffentliche Kasimir-API ist OpenAI-kompatibel: Fehler werden im selben JSON-Format wie bei OpenAI zurückgegeben, damit handelsübliche OpenAI-SDKs sie ganz normal als Exception bzw. Fehlerobjekt anzeigen. Dieses Kapitel beschreibt exakt, welche Status-Codes die Endpunkte unter /api/v1/* werfen, was sie bedeuten, wie das Fehlerobjekt aufgebaut ist und welche harten Grenzen (Budget, Payload-Größen) gelten – alles direkt aus dem Quellcode abgeleitet.

Fehlerformat

Alle Fehler der OpenAI-kompatiblen Endpunkte (POST /v1/chat/completions, POST /v1/embeddings, GET /v1/models) werden von server/utils/apiError.ts (toOpenaiError) in das OpenAI-Schema übersetzt:

{
  "error": {
    "message": "Model \"foo\" not found",
    "type": "not_found_error",
    "code": null
  }
}

Feld

Inhalt

message

Klartext aus statusMessage der geworfenen createError; bei unbekannten Fehlern "Internal error".

type

Aus dem Status-Code abgeleitet (siehe Tabelle unten).

code

Immer null (Kasimir vergibt keine maschinellen Fehlercodes in Phase 1).

Der type-Wert wird strikt aus dem Status-Code gemappt:

Status

type

401

authentication_error

402

insufficient_quota

403

permission_error

404

not_found_error

≥ 500

api_error

alle anderen (z. B. 400, 409)

invalid_request_error

ℹ️

Der HTTP-Status-Code und der type im Body sind immer konsistent – toOpenaiError setzt beide aus derselben Quelle (setResponseStatus + Mapping).

⚠️

Sonderfall Streaming: Tritt ein Fehler nachdem der SSE-Stream begonnen hat auf (started = true in chat/completions.post.ts), kann er nicht mehr in ein OpenAI-Fehlerobjekt umgeformt werden. Der Stream bricht dann einfach ab. Behandle einen unerwartet endenden Stream client-seitig als Fehler.

Status-Codes im Detail

Die folgende Tabelle listet jeden Status-Code, der von der /api/v1/*-Oberfläche geworfen wird, samt auslösender Code-Stelle und Bedeutung.

Status

type

Wann

Quelle

400

invalid_request_error

Body verletzt das Zod-Schema (model/messages/input fehlt oder falsch typisiert); fehlende Router-id; Assistant ohne Modell

*.post.ts (safeParse), assistants/[id]/run.post.ts

401

authentication_error

Kein Authorization: Bearer … Header; Schlüssel unbekannt; Schlüssel widerrufen (revoked_at)

apiKeyAuth.ts

402

insufficient_quota

Monatsbudget der Firma erreicht/überschritten

apiUsage.ts (assertCompanyBudget)

403

permission_error

Schlüssel besitzt nicht den benötigten Scope (z. B. chat:write); Modell ist nicht-EU und die Firma hat non-EU nicht freigeschaltet

apiKeyAuth.ts, apiModelResolve.ts

404

not_found_error

Modell-Slug unbekannt/inaktiv/falsche Purpose; Modell per disabled_model_slugs gesperrt; Assistant existiert nicht oder gehört einer anderen Firma

apiModelResolve.ts, assistants/[id]/run.post.ts

409

invalid_request_error

Nur Schlüssel-Verwaltung: Name bereits vergeben (23505)

company/api-keys.post.ts

502

api_error

Upstream (LiteLLM) liefert keinen Erfolg und keinen eigenen Status – Fallback `

5xx (durchgereicht)

api_error

Upstream-Fehler mit eigenem Status (res.status) – z. B. LiteLLM 500

chat/completions.post.ts, embeddings.post.ts

500

api_error

Jeder nicht klassifizierte Fehler (Default in toOpenaiError)

apiError.ts

💡

402 bedeutet nicht „pro Anfrage zu teuer“, sondern „Firmen-Monatsbudget aufgebraucht“. Der Verbrauch summiert API- und In-App-Chat-Nutzung des laufenden Kalendermonats (RPC company_month_spend_eur).

401 – Authentifizierung

authenticateApiKey (server/utils/apiKeyAuth.ts) wirft 401 in drei Fällen:

  • Kein Bearer-Tokenmessage: "Missing bearer token"

  • Ungültiger Schlüssel – Hash nicht in company_api_keys gefunden – message: "Invalid API key"

  • Widerrufener Schlüsselrevoked_at gesetzt – message: "API key revoked"

Schlüssel haben das Format kasi_<32 Zeichen> und werden nur als SHA-256-Hash gespeichert; der Klartext ist einmalig bei der Erstellung sichtbar.

402 – Budget

assertCompanyBudget (server/utils/apiUsage.ts) prüft vor dem Forwarding an den Upstream:

  • companies.monthly_budget_eur ist null oder ≤ 0unbegrenzt, kein Limit.

  • Andernfalls wird der Monatsverbrauch via company_month_spend_eur ermittelt. Ist used ≥ budget, kommt 402 mit z. B. Monthly budget of €100.00 reached (used €100.42).

ℹ️

Fail-open bei Infrastruktur-Fehlern: Schlägt die Budget-Abfrage selbst fehl (DB-Glitch), wird die Anfrage durchgelassen statt blockiert – nur ein echtes 402 (Budget überschritten) wird durchgereicht. Eine flaky Abfrage sperrt einen Kunden also nie aus.

403 – Berechtigung

Zwei unabhängige Ursachen:

  • Fehlender ScopeauthenticateApiKey(event, ['chat:write']) wirft Missing scope: chat:write, wenn dem Schlüssel der nötige Scope fehlt. GET /v1/models erfordert keinen speziellen Scope; chat/completions und embeddings erfordern chat:write.

  • Non-EU-GateresolveApiModel wirft 403, wenn das Modell eu_hosted = false ist und companies.allow_non_eu_models nicht true ist: Model "…" is not enabled for your organization (non-EU model).

404 – Nicht gefunden

resolveApiModel (Chat/Embeddings) bzw. der Assistant-Handler werfen 404, wenn:

  • der Slug in models nicht existiert, inaktiv ist oder eine andere Purpose hat (chat vs. embedding),

  • der Slug in companies.disabled_model_slugs steht (wird bewusst als „not found“ getarnt),

  • ein Assistant (/v1/assistants/{id}/run) nicht existiert oder einer fremden Firma gehört (Tenant-Isolation),

  • das Assistant-Modell nicht existiert/inaktiv ist – Model "…" not found or inactive.

502 / durchgereichte 5xx – Upstream

Antwortet die LiteLLM-Schicht nicht mit 2xx (oder fehlt der Body beim Streaming), wirft Kasimir res.status || 502 mit Upstream error: <erste 200 Zeichen der Upstream-Antwort>. Bei 502 ist die Ursache typischerweise, dass der Upstream gar keinen verwertbaren Status lieferte.

Request-Lebenszyklus POST /api/v1/chat/completions Anfrage 1 Bearer-Auth Token prüfen 401 2 Scope-Check Berechtigung 403 3 Modell + EU Auflösen / Gate 404/403 4 Budget Firmen-Limit 402 5 LiteLLM Upstream-Call 502/5xx 200 OK · OpenAI-Body { "object":"chat.completion", "model":"chat1-gemma", "choices":[ … ], "usage":{ … } } 401 { "error": { message: "Ungültiger API-Schlüssel", type: "invalid_ request_error", code: null } } 403 { "error": { message: "Scope fehlt", type: "permission _error", code: null } } 404/403 { "error": { message: "Modell nicht verfügbar", type: "model_not _found", code: null } } 402 { "error": { message: "Budget erschöpft", type: "insufficient _quota", code: null } } 502/5xx { "error": { message: "Upstream nicht erreichbar", type: "api_error", code: null } } Legende Erfolgspfad (Gate bestanden) Fehler-Abzweig (Short-Circuit) Gate-Nummer · sequenzielle Prüfung
Anfrage-Lebenszyklus: an welcher Stufe welcher Status-Code entsteht.

Limits

In Phase 1 gibt es keine Rate-Limits und keine 429-Antworten – pro-Key-Spend-Caps und pro-Key-Rate-Limits sind ausdrücklich auf Phase 2 verschoben. Das einzige durchgesetzte „Mengen“-Limit ist das Firmen-Monatsbudget (siehe 402). Daneben gelten Payload-Schemagrenzen:

Limit

Wert

Endpunkt

Quelle

Monatsbudget (Firma)

companies.monthly_budget_eur; null/≤0 = unbegrenzt

chat, embeddings

assertCompanyBudget

messages (min.)

mindestens 1 Nachricht

/v1/chat/completions

Zod .min(1)

Assistant-messages

1 bis 50 Nachrichten

/v1/assistants/{id}/run

Zod .min(1).max(50)

Assistant-temperature

0 bis 2

/v1/assistants/{id}/run

Zod .min(0).max(2)

Assistant-max_tokens

1 bis 32000 (Integer)

/v1/assistants/{id}/run

Zod .min(1).max(32000)

Rate-Limit / 429

nicht vorhanden (Phase 2)

Spec §Non-Goals

⚠️

Für chat/completions und embeddings werden temperature, max_tokens, tools, response_format usw. nicht von Kasimir validiert, sondern verbatim an den Upstream durchgereicht (.passthrough()). Ungültige Werte führen daher zu einem durchgereichten Upstream-Fehler (z. B. 400/5xx), nicht zu einem Kasimir-400.

Fehlerbehandlung (Empfehlungen)

Status

Reaktion

400

Request-Body korrigieren; nicht erneut versuchen (deterministisch).

401

Schlüssel prüfen/erneuern; widerrufene Schlüssel in der App neu anlegen.

402

Budget in Administration → … anheben oder bis zum Monatswechsel warten; Retry zwecklos.

403

Scope des Schlüssels prüfen bzw. EU-Gate (allow_non_eu_models) klären – beides nur durch Owner/Admin änderbar.

404

Modell-Slug gegen GET /v1/models abgleichen; Assistant-ID/Firma prüfen.

429

Tritt aktuell nicht auf – keine Behandlung nötig (kommt erst in Phase 2).

502 / 5xx

Transienter Upstream-Fehler – mit Backoff erneut versuchen.

Da das Fehlerformat OpenAI-konform ist, fängt jedes OpenAI-SDK diese Fälle automatisch ab – z. B. wirft das Python-SDK AuthenticationError (401), PermissionDeniedError (403), NotFoundError (404) und APIStatusError (5xx). Auf error.message lässt sich der konkrete Grund auslesen.