Skip to main content
The SDK splits failures into four layers with a strict rule about which throw and which come back as a result. Use typed error classes (not string matching) to branch, and let the structured logger surface retries so nothing is silent.

Typed errors

Branch on error class, not on .message. Every error carries a stable .code, the run’s .traceId (when applicable), and a server-adjudicated .retryable flag.
Hierarchy:

The four failure layers

Read this rule carefully. If a Flow runs but fails mid-execution, the SDK does not throw — it returns { status: "failed", traceId, outputs: <partial>, failure: {...}, notices: [...] }. Silent try/catch that swallows only exceptions will miss these. Always check .status on the return value of flows.run.

Why the split

Anything that means “the request didn’t reach the graph” throws, so your caller code fails loud and early. Anything that means “the graph ran but the answer isn’t clean” comes back as a result, so you get:
  • the traceId for the trace UI and for feedback / signals.report,
  • whatever partial outputs were produced,
  • a machine-readable failure.code for retry / degrade decisions,
  • constraint notices[] that shaped the run (surface these in your admin UI, not to end users).

Logging

Structured and redaction-first by default — tokens, secrets, onBehalfOf values, and request/response bodies do not land in logs unless you turn debug: true on.
Retries are always logged — each attempt records attempt, the failure code, and the decision. No silent retries. Recommended:
  • Route logger at Nora’s stream (pino / winston / bunyan) so log level and destination match the rest of your service.
  • Wire onLog into your metrics — retry rate, circuit-open rate, and provider-fallback frequency are the leading indicators when something upstream is degrading.
  • Keep debug off in production. Turn it on per-request via a scoped clone when reproducing an incident.

Common patterns

Retry only on retryable

Degrade on partial

Distinguish feedback from signals.report

Mixing these means detectors and clusters get noisy — keep the intents separate.