Skip to main content
The SDK distinguishes between two classes of failures:
  1. Initial sync failures - surfaced via NexusInitError from NexusProvider. Handle with an Error Boundary or the onError render prop.
  2. Background sync / SSE failures - never thrown. They are logged via NexusLogger.error(...), and the existing cache continues to be served.

Error hierarchy

All SDK errors extend NexusError. A single instanceof check covers everything:
The full hierarchy:

When each is thrown

Hooks vs imperative - non-throwing vs throwing

A subtle but deliberate API decision:
Why? React component code reads from the cache on every render. If useSecret threw on a public key, every render would throw, breaking the component tree. The hook trades type safety (no string guarantee) for ergonomic component code.

Handling NexusInitError

Error Boundary (idiomatic React)

onError render prop

Inline handling without an Error Boundary:

What is NOT thrown

  • Background syncs - silently retried on the next TTL tick. Cache served.
  • SSE transport errors - the SDK reconnects with exponential backoff, then falls back to TTL polling after 3 consecutive failures. No exception surfaces.
  • 304 Not Modified - treated as success; TTL reset.
  • Hook reads for missing/inaccessible keys - return undefined (or the defaultValue for useFlag).

SSE-specific behaviour

SSE failures never propagate to your code. Use useNexusStreamStatus() to detect “live updates are no longer available”:

5xx exponential backoff (v0.3.1+)

When the server returns a 5xx status on /sync, the SDK:
  1. Catches the response internally and surfaces it as a NexusServerError(status, bodySnippet).
  2. Increments an internal attempt counter and schedules a retry via setTimeout with exponential backoff:
  3. Emits FALLBACK_REASON_TRANSPORT on the stream observer during the wait.
  4. On the next successful sync - including the auto-retry succeeding - resets the counter.