livestorejs/livestore

Boot: schema‑mismatch event payloads trigger Die and stop backend pulling

Open

#732 opened on Oct 7, 2025

View on GitHub
 (0 comments) (0 reactions) (0 assignees)TypeScript (128 forks)github user discovery
bugerror-handlinghelp wantedsyncingtestingtype:bug

Repository metrics

Stars
 (3,599 stars)
PR merge metrics
 (PR metrics pending)

Description

Boot: schema‑mismatch event payloads trigger Die and stop backend pulling

Summary

  • When the sync backend delivers an event whose args don’t match the event’s schema, a ParseError bubbles up as a Defect (Die). During boot this occurs inside the backend‑pulling fiber and results in the fiber terminating. The log shows “Ignoring sync error (Die)”, but pulling then stops, potentially stalling boot.

Evidence

  • Runtime log excerpt:
    • DEBUG: “Ignoring sync error (Die)” followed by ParseError for invalid field:
      • Expected number, actual null for issueId
  • Relevant code paths:
    • packages/@livestore/common/src/materializer-helper.ts:38 (Schema.decodeUnknownSync in getExecStatementsFromMaterializer)
    • packages/@livestore/common/src/materializer-helper.ts:102 (dev-only hash via makeMaterializerHash)
    • packages/@livestore/common/src/leader-thread/LeaderSyncProcessor.ts:774 (computing materializerHashLeader inside pull tap)
    • packages/@livestore/common/src/leader-thread/materialize-event.ts:65 (non-dev materialization also decodes args)
    • packages/@livestore/common/src/leader-thread/LeaderSyncProcessor.ts:262 (catch-all cause handler logs and returns)

Observed Behavior

  • Malformed event payload → Schema.decodeUnknownSync throws → effect dies in backend‑pulling tap → handler logs and returns → pulling fiber terminates → no further upstream progress; boot may not complete.

Real-World Trigger

  • Example app events enforce numeric fields (e.g. issueId). If upstream sends null for a numeric field, decoding fails.

Reproduction (tests)

  • Location: tests/package-common/src/leader-thread/malformed-events.test.ts
  • Steps:
    • Start leader with default onSyncError: 'ignore' and live pull.
    • Mock backend: advance a malformed event (e.g., name matches schema but a numeric field is null).
    • Then advance a valid event.
  • Current behavior: logs include “Ignoring sync error (Die)”; subsequent valid event is not processed (pulling stalled).
  • Expected behavior: no Die; pulling stays alive; subsequent valid event is processed.

Impact

  • Boot reliability: initial sync can stall.
  • Sync robustness: a single malformed event terminates pulling.
  • Developer experience: dev-only hash path surfaces earlier, but same failure possible at materialization.

Expected Behavior

  • Malformed event payloads are handled intentionally without unhandled defects.
  • With onSyncError: 'ignore', log a structured, expected error and continue pulling.
  • Boot completes; subsequent valid events are processed.

Acceptance Criteria

  • Reproduced failure covered by a test under tests/package-common/src/leader-thread.
  • Schema mismatch does not terminate backend pulling.
  • Error surfaced as expected, structured error (not a Defect), with clear context.
  • Boot proceeds and sync continues with subsequent valid events.

Filed by an assistant on behalf of the user.

Contributor guide