Fehlerbehandlung
Diese Seite richtet sich an Entwickler. Sie beschreibt, wie das Paket @ai-systems-manager/sdk Fehler meldet, welche Codes es gibt und wie man auf sie reagiert. Wer das SDK zuerst einrichten will, liest SDK einrichten und aufrufen; zum Routing- und Failover-Verhalten siehe Routing und Failover.
Die AsmError-Klasse
Abschnitt betitelt „Die AsmError-Klasse“Jeder Fehler, den das SDK auslöst, ist ein AsmError. Die Klasse erbt von Error und trägt zusätzlich vier Felder:
| Feld | Typ | Inhalt |
|---|---|---|
code | AsmErrorCode | Maschinenlesbarer Code (siehe Tabelle unten). Der stabile Diskriminator für Fallunterscheidungen. |
message | string | Menschenlesbare Beschreibung. Nicht für Fallunterscheidungen verwenden. |
details | Record<string, unknown> (optional) | Strukturierte Zusatzinformationen, je nach Code unterschiedlich (z. B. providerChain). |
requestId | string (optional) | Aus dem x-request-id-Antwort-Header übernommen. Verknüpft den Fehler mit dem Audit-Trail. |
Fang AsmError ab, prüfe err instanceof AsmError und verzweige über err.code:
import { AsmError } from '@ai-systems-manager/sdk'
try { const result = await asm.invoke<OutputType>(featureId, input) return result.data} catch (err) { if (err instanceof AsmError) { switch (err.code) { case 'UNAUTHORIZED': case 'FORBIDDEN': // Token prüfen / erneuern break case 'RATE_LIMITED': // zurückstellen und später erneut versuchen break case 'ALL_PROVIDERS_EXHAUSTED': // siehe Abschnitt unten — providerChain auswerten break case 'OUTPUT_SCHEMA_VIOLATION': // Modell-Ergebnis passt nicht zum Contract-Schema break default: // restliche Codes generisch behandeln break } console.error(err.code, err.message, err.requestId) } throw err}Fehler-Codes
Abschnitt betitelt „Fehler-Codes“code ist ein Wert vom Typ AsmErrorCode. Die Konstante ASM_ERROR_CODES enthält alle Codes als benannte Felder und lässt sich aus dem Paket importieren. Die HTTP-Statuscodes in Klammern zeigen, aus welcher Plattform-Antwort der jeweilige Code abgeleitet wird.
Validierung und Authentifizierung
Abschnitt betitelt „Validierung und Authentifizierung“| Code | Bedeutung | Typische Ursache |
|---|---|---|
VALIDATION_ERROR | Eingabe ungültig | Leere baseUrl oder leeres token bei der Client-Erstellung; featureId entspricht nicht dem Format feat_ + 26-Zeichen-ULID. |
UNAUTHORIZED (401) | Nicht authentifiziert | Token fehlt, ist abgelaufen oder ungültig. |
FORBIDDEN (403) | Nicht berechtigt | Token darf dieses Feature nicht aufrufen. |
NOT_FOUND (404) | Feature nicht gefunden | Unbekannte featureId oder kein aktiver Contract. |
FEATURE_SUNSET (410) | Feature stillgelegt | Das Feature wurde abgekündigt und ist nicht mehr aufrufbar. |
Rate-Limit und Verfügbarkeit
Abschnitt betitelt „Rate-Limit und Verfügbarkeit“| Code | Bedeutung | Typische Ursache |
|---|---|---|
RATE_LIMITED (429) | Rate-Limit erreicht | Zu viele Anfragen. Wird intern mit exponentiellem Backoff behandelt; bleibt es bestehen, wird der Code geworfen. |
SERVICE_UNAVAILABLE (503) | Plattform vorübergehend nicht verfügbar | Wartung oder Überlast auf Plattformseite. |
INTERNAL_ERROR | Unerwarteter Fehler | Nicht näher klassifizierte Plattform-Antwort (Standard-Abbildung für unbekannte Statuscodes). |
Netz, Provider und Schema
Abschnitt betitelt „Netz, Provider und Schema“| Code | Bedeutung | Typische Ursache |
|---|---|---|
NETWORK_ERROR | Netzwerkfehler | Verbindung zur Plattform oder zum Provider fehlgeschlagen (DNS, TLS, Timeout auf Transportebene). |
PROVIDER_ERROR | Provider-Fehler | Der Provider-Aufruf schlug fehl oder wurde abgebrochen, ohne dass eine Failover-Kette griff. |
OUTPUT_SCHEMA_VIOLATION | Schema-Verletzung | Das Modell-Ergebnis passt auch nach den Schema-Retries nicht zum Output-Schema des Contracts. |
CONTRACT_UNAVAILABLE | Contract nicht nutzbar | Contract konnte nicht geladen werden oder Provider-Credentials im Contract fehlen. |
Routing
Abschnitt betitelt „Routing“| Code | Bedeutung | Typische Ursache |
|---|---|---|
ALL_PROVIDERS_EXHAUSTED | Alle Provider erschöpft | Primärer Provider und gesamte Fallback-Kette sind fehlgeschlagen. details.providerChain listet jeden Versuch. |
MULTI_MODAL_NOT_SUPPORTED_BY_PROVIDER | Multi-Modal vom Provider nicht unterstützt | Binäre Eingabe (z. B. Bild), aber der primäre Provider hat die nötige Fähigkeit (z. B. Vision) nicht. |
MULTI_MODAL_NOT_SUPPORTED_BY_FALLBACK | Multi-Modal vom Fallback nicht unterstützt | Wie oben, aber auf einem Provider der Fallback-Kette. |
INVALID_TRAFFIC_SPLIT | Ungültiger Traffic-Split | Die Phased-Rollout-Konfiguration des Contracts ist inkonsistent. |
| Code | Bedeutung | Typische Ursache |
|---|---|---|
TOOL_NOT_ALLOWED | Tool nicht erlaubt | Das Modell rief ein Tool auf, das der Contract nicht freigibt. |
SCHEMA_VIOLATION | Tool-Argumente ungültig | Die vom Modell erzeugten Tool-Argumente passen nicht zum Tool-Schema. |
TOOL_EXECUTOR_MISSING | Tool-Executor fehlt | Für ein erlaubtes Tool ist keine Implementierung registriert. |
TOO_MANY_TOOL_CALLS | Zu viele Tool-Aufrufe | Die Obergrenze an Tool-Aufrufen pro Invoke wurde überschritten. |
ALL_PROVIDERS_EXHAUSTED genauer
Abschnitt betitelt „ALL_PROVIDERS_EXHAUSTED genauer“Antwortet der primäre Provider mit 5xx oder überschreitet er die failoverDeadlineMs, wechselt das SDK transparent zum nächsten Provider der Kette. Schlagen primärer Provider und alle Fallbacks fehl, wirft das SDK ALL_PROVIDERS_EXHAUSTED. In details stehen dann zwei Felder:
details.providerChain: ein Array mit einem Eintrag pro Versuch. Jeder Eintrag hatprovider,model,latencyMs,successund — bei Fehlschlag — einerror-Objekt mitcode,messageund optionalstatusCode.details.lastKnownGood: beschreibt die letzte erfolgreiche Antwort für dieselbefeatureIdinnerhalb der Lebensdauer dieses Client-Objekts — mitcompletedAt(Zeitstempel) undageMs(Alter). Das Feld ist ein Deskriptor, nicht die Nutzlast: Es enthält nicht die alte Antwort selbst.
So liest du die Versuchs-Kette aus:
import { AsmError } from '@ai-systems-manager/sdk'
interface ProviderChainAttempt { provider: string model: string latencyMs: number success: boolean error?: { code: string; message: string; statusCode?: number }}
try { await asm.invoke<OutputType>(featureId, input)} catch (err) { if (err instanceof AsmError && err.code === 'ALL_PROVIDERS_EXHAUSTED') { const chain = (err.details?.providerChain ?? []) as ProviderChainAttempt[] for (const attempt of chain) { console.error( `${attempt.provider}/${attempt.model}: ` + `${attempt.success ? 'ok' : attempt.error?.code} ` + `(${attempt.latencyMs} ms)`, ) } } throw err}Timeouts und Abbruch
Abschnitt betitelt „Timeouts und Abbruch“Zwei Zeitbudgets begrenzen einen Aufruf, dazu kommt ein optionales eigenes Abbruch-Signal:
| Mechanismus | Default | Wirkung |
|---|---|---|
invokeTimeoutMs | 30 s | Harte Obergrenze pro Provider. Antwortet ein Provider nicht innerhalb dieser Zeit, wird sein Aufruf abgebrochen. |
failoverDeadlineMs | 5 s | Deadline des primären Providers. Überschreitet er sie, wechselt das SDK zum nächsten Provider — ohne Code-Änderung. |
options.signal | — | Ein eigenes AbortSignal, das du pro Aufruf übergeben kannst, um ihn von außen abzubrechen. |
const controller = new AbortController()setTimeout(() => controller.abort(), 10_000)
const result = await asm.invoke<OutputType>(featureId, input, { signal: controller.signal,})Beide Zeitbudgets lassen sich global in der Client-Konfiguration setzen und pro Aufruf über options.failoverDeadlineMs bzw. options.primaryTimeoutMs überschreiben. Details zu den Optionen stehen unter SDK einrichten und aufrufen und Routing und Failover.
Schema-Retry und Backoff
Abschnitt betitelt „Schema-Retry und Backoff“Bei einer Schema-Verletzung wird derselbe Provider bis zum schemaRetryBudget (Default 3, Maximum 10, 0 schaltet ab) erneut versucht; bleibt das Ergebnis falsch, wirft das SDK OUTPUT_SCHEMA_VIOLATION. Ein 429 (Rate-Limit) wird mit exponentiellem Backoff behandelt, bevor RATE_LIMITED geworfen wird. Beides ist genauer beschrieben unter SDK einrichten und aufrufen (Schema-Kompatibilität) und Routing und Failover (Backoff und Failover).
requestId für den Audit-Trail
Abschnitt betitelt „requestId für den Audit-Trail“Ein AsmError kann eine requestId tragen, die aus dem x-request-id-Antwort-Header der Plattform stammt. Mit ihr findest du einen fehlgeschlagenen Aufruf im Audit-Trail wieder — etwa um die Provider-Kette oder die Plattform-Entscheidung nachzuvollziehen.
catch (err) { if (err instanceof AsmError) { console.error(`asm error ${err.code} (request ${err.requestId ?? 'n/a'})`) }}Logge die requestId zusammen mit dem code. Wie der Audit-Trail aufgebaut ist und wonach er sich durchsuchen lässt, beschreibt Audit.
- Zur Einrichtung und zu allen Konfigurationsfeldern: SDK einrichten und aufrufen.
- Zu Provider-Routing, Failover und Phased-Rollout: Routing und Failover.
- Zu Spans, Metriken und der requestId im Kontext: Observability.