detail is optional and only ever present in mode: 'development' — see below.
Modes
mode: 'development' | 'production', default 'production' unless NODE_ENV === 'development'.
This fail-safe default matters: a host that forgets to set mode explicitly gets the safer,
detail-hiding behavior automatically.
Two-tier trust model
- Errors already curated into a developer-facing message pass through as-is:
RuntimeHttpError— routing/validation errors this runtime raises itself (bad route, missing required field, malformed body, etc.).PersonaApiError/PersonaAuthError/PersonaValidationErrorfrom@personaai/sdk— these already carry a safemessageand machine-readablecodefrom the Persona API itself.- In both cases,
detail(the upstream response envelope, where applicable) is only attached inmode: 'development'— the curatedmessage/codeare always present regardless of mode.
- Anything else is treated as untrusted — a bug in your own hook code, a raw network error, an
unexpected exception from deep inside a dependency:
- Always
500/INTERNAL_ERROR. mode: 'production': a fixed generic message, no stack, no internal detail.mode: 'development': the real message and stack underdetail.
- Always
Mid-stream failures
If a/chat or /architect stream fails after headers are already committed (SSE has started),
the runtime cannot change the HTTP status code retroactively. Instead it synthesizes a sanitized
RUN_ERROR AG-UI event as the last frame of the stream, following the same two-tier trust rule for
what that event’s message contains. The corresponding lifecycle hook
behavior: this is treated as a normal completed run (afterRun fires with
result.erroredInBand: true), not a thrown exception (onError does not fire) — see
Lifecycle hooks for the full explanation.