Zum Inhalt springen

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.

Jeder Fehler, den das SDK auslöst, ist ein AsmError. Die Klasse erbt von Error und trägt zusätzlich vier Felder:

FeldTypInhalt
codeAsmErrorCodeMaschinenlesbarer Code (siehe Tabelle unten). Der stabile Diskriminator für Fallunterscheidungen.
messagestringMenschenlesbare Beschreibung. Nicht für Fallunterscheidungen verwenden.
detailsRecord<string, unknown> (optional)Strukturierte Zusatzinformationen, je nach Code unterschiedlich (z. B. providerChain).
requestIdstring (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
}

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.

CodeBedeutungTypische Ursache
VALIDATION_ERROREingabe ungültigLeere baseUrl oder leeres token bei der Client-Erstellung; featureId entspricht nicht dem Format feat_ + 26-Zeichen-ULID.
UNAUTHORIZED (401)Nicht authentifiziertToken fehlt, ist abgelaufen oder ungültig.
FORBIDDEN (403)Nicht berechtigtToken darf dieses Feature nicht aufrufen.
NOT_FOUND (404)Feature nicht gefundenUnbekannte featureId oder kein aktiver Contract.
FEATURE_SUNSET (410)Feature stillgelegtDas Feature wurde abgekündigt und ist nicht mehr aufrufbar.
CodeBedeutungTypische Ursache
RATE_LIMITED (429)Rate-Limit erreichtZu viele Anfragen. Wird intern mit exponentiellem Backoff behandelt; bleibt es bestehen, wird der Code geworfen.
SERVICE_UNAVAILABLE (503)Plattform vorübergehend nicht verfügbarWartung oder Überlast auf Plattformseite.
INTERNAL_ERRORUnerwarteter FehlerNicht näher klassifizierte Plattform-Antwort (Standard-Abbildung für unbekannte Statuscodes).
CodeBedeutungTypische Ursache
NETWORK_ERRORNetzwerkfehlerVerbindung zur Plattform oder zum Provider fehlgeschlagen (DNS, TLS, Timeout auf Transportebene).
PROVIDER_ERRORProvider-FehlerDer Provider-Aufruf schlug fehl oder wurde abgebrochen, ohne dass eine Failover-Kette griff.
OUTPUT_SCHEMA_VIOLATIONSchema-VerletzungDas Modell-Ergebnis passt auch nach den Schema-Retries nicht zum Output-Schema des Contracts.
CONTRACT_UNAVAILABLEContract nicht nutzbarContract konnte nicht geladen werden oder Provider-Credentials im Contract fehlen.
CodeBedeutungTypische Ursache
ALL_PROVIDERS_EXHAUSTEDAlle Provider erschöpftPrimärer Provider und gesamte Fallback-Kette sind fehlgeschlagen. details.providerChain listet jeden Versuch.
MULTI_MODAL_NOT_SUPPORTED_BY_PROVIDERMulti-Modal vom Provider nicht unterstütztBinä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_FALLBACKMulti-Modal vom Fallback nicht unterstütztWie oben, aber auf einem Provider der Fallback-Kette.
INVALID_TRAFFIC_SPLITUngültiger Traffic-SplitDie Phased-Rollout-Konfiguration des Contracts ist inkonsistent.
CodeBedeutungTypische Ursache
TOOL_NOT_ALLOWEDTool nicht erlaubtDas Modell rief ein Tool auf, das der Contract nicht freigibt.
SCHEMA_VIOLATIONTool-Argumente ungültigDie vom Modell erzeugten Tool-Argumente passen nicht zum Tool-Schema.
TOOL_EXECUTOR_MISSINGTool-Executor fehltFür ein erlaubtes Tool ist keine Implementierung registriert.
TOO_MANY_TOOL_CALLSZu viele Tool-AufrufeDie Obergrenze an Tool-Aufrufen pro Invoke wurde überschritten.

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 hat provider, model, latencyMs, success und — bei Fehlschlag — ein error-Objekt mit code, message und optional statusCode.
  • details.lastKnownGood: beschreibt die letzte erfolgreiche Antwort für dieselbe featureId innerhalb der Lebensdauer dieses Client-Objekts — mit completedAt (Zeitstempel) und ageMs (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
}

Zwei Zeitbudgets begrenzen einen Aufruf, dazu kommt ein optionales eigenes Abbruch-Signal:

MechanismusDefaultWirkung
invokeTimeoutMs30 sHarte Obergrenze pro Provider. Antwortet ein Provider nicht innerhalb dieser Zeit, wird sein Aufruf abgebrochen.
failoverDeadlineMs5 sDeadline des primären Providers. Überschreitet er sie, wechselt das SDK zum nächsten Provider — ohne Code-Änderung.
options.signalEin 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.

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).

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.