Troubleshooting

Start by identifying the failing layer and the last successful step. When DevTools is available, inspect the prepaint, model, or tx category together with the transaction or model identifier.

Prepaint does not replay

SymptomLikely causeNext action
Every visit is a cold startNo stored snapshot or a different route keyRevisit the same route and inspect the restore event strategy
Snapshot is discarded immediatelyMissing fields, corruption, or policy mismatchInspect storage.error and cold-start restore, then create a new snapshot
Stale sensitive content is visibleMissing sensitive or volatile markerMark the element for scrubbing or volatility and refresh the stored snapshot
UI jumps after handoffLarge difference between snapshot and current React UIMeasure replay and handoff timing and reduce volatile regions

The Prepaint overlay is non-interactive. Clicks being unavailable during replay is expected behavior.

Local-First data is not ready

  • useModel synchronously returns the in-memory external-store snapshot, while IndexedDB loading is asynchronous. Handle the initial loading state.
  • When stored data fails the Zod schema, a validation.error event is emitted and the stored value may be removed.
  • useSuspenseSyncedModel throws the Promise returned by getSyncPromise() when both data and error are absent. Provide both an ErrorBoundary and a Suspense fallback.
  • When broadcast.fallback or broadcast.skipped appears, do not assume live cross-tab updates. Provide refresh or manual sync.

StorageError.code uses the STORAGE_* namespace. Read the raw classification from storageCode, operation details from storageContext, and recovery status from isRecoverable().

Tx ends in rollback or timeout

  • The failing step's compensate function is not called. Only completed steps are compensated in reverse order.
  • If a step ignores AbortSignal, the underlying work can continue after timeout. Pass the signal to cancellable APIs.
  • RetryExhaustedError means all configured attempts were used. Check server state and idempotency before repeating the request.
  • CompensationFailedError.failures contains compensation errors only. Use completedSteps with the DevTools timeline to decide the manual recovery scope.
Atomicity boundary

Tx compensates completed client work in reverse order, but it does not make every external system atomic. Pair irreversible operations such as payment or inventory changes with server transactions or idempotency contracts.

DevTools fields are missing or different

Some runtime payload fields differ from the bridge types. For example, a Tx start event may use timeout while the bridge type uses timeoutMs, or hasCompensate while the type uses hasCompensation.

  • Treat runtime package emitters as the observable contract.
  • Prefer short diagnostic sessions because long sessions and large payload searches increase memory and serialization cost.
  • Interpret step.success.attempt with the transaction timeline because it can reflect configuration rather than the actual attempt count.

Recovery by error type

ErrorDefault classificationResponse
StorageErrorFollow isRecoverable()Show the user message and offer retry or refresh
ValidationErrorRecoverableCheck stored schema and version, then sync valid data
TransactionTimeoutErrorRecoverableCheck signal propagation and timeout budget
RetryExhaustedErrorRecoverableCheck server state and retry policy before explicit retry
CompensationFailedErrorNon-recoverableUse failures, completedSteps, and timeline for manual recovery
TransactionStateErrorNon-recoverableRemove duplicate calls against an already completed transaction

See Reference for exact properties and exports, and DevTools for observation workflows.