Skip to content

Don't let a corrupt JSON state file crash server startup (#204)#205

Open
KunjShah95 wants to merge 1 commit into
andrewyng:mainfrom
KunjShah95:fix/json-store-startup-resilience
Open

Don't let a corrupt JSON state file crash server startup (#204)#205
KunjShah95 wants to merge 1 commit into
andrewyng:mainfrom
KunjShah95:fix/json-store-startup-resilience

Conversation

@KunjShah95

Copy link
Copy Markdown

What

Makes the small JSON-backed stores survive a corrupt/truncated state file instead of crashing server startup, and makes their writes atomic so they stop producing those corrupt files.

Fixes #204. Same failure mode as #158, generalized beyond selfwake.py (which #159 handles).

Why

Every one of these stores loaded its file with an unguarded json.loads in __init__, and all are constructed eagerly in SessionManager.__init__. So one malformed file raised out of the constructor and aborted startup — recoverable only by manually deleting the file. Several also wrote non-atomically (write_text in place), which is exactly what leaves a truncated file after a crash/kill/disk-full mid-write. The two defects compound.

How

New coworker/jsonstore.py with two helpers, generalizing the pattern already used inline by ChannelBuffer and WorkspaceTrustStore:

  • read_json(path, default) — missing/corrupt file → default, moving the bad file aside to <name>.corrupt (preserved for inspection, not re-hit on the next boot).
  • write_json_atomic(path, data) — temp sibling + os.replace (atomic on POSIX and Windows).

Applied to: InboxStore, InboxRouting, MentionSessionStore, SubscriptionStore, UnroutedStore, UnattendedRegistry, PersonaConnectionStore, SessionConnectionStore, RiskOverrideStore.

Left untouched (already resilient — the precedent this follows): ChannelBuffer, ParkedStore, WorkspaceTrustStore. Not touched: selfwake.py (handled by #159, to avoid conflict).

Tests

tests/test_json_store_resilience.py covers the helpers (missing/valid/corrupt/atomic/no-temp-leftover) and each store's construct-from-corrupt-file path plus a save round-trip. 16 passed locally, along with the existing test_inbox_routing suite.

Note: the full manager-level suites (test_connections, test_subscriptions) import coworker.server.manager, which pulls the aisuite git dependency I couldn't install in my sandbox — so those weren't run locally; CI covers them. The changed store modules are pure-stdlib and their behavior is exercised directly by the new tests.

Out of scope

Schema-drift tolerance (a dataclass gaining/losing a field across versions) is a separate concern and not addressed here.

🤖 Generated with Claude Code

The small file-backed stores (Inbox, inbox routing, mention threads, channel
subscriptions, unrouted/dead-letter, unattended flags, per-persona/per-session
connection maps, and user risk overrides) each loaded their JSON file with an
unguarded json.loads inside __init__ — and every one is constructed eagerly in
SessionManager.__init__. So a single truncated or malformed file turned into an
exception that aborted server startup entirely, recoverable only by finding and
deleting the file by hand. Several of the same stores also wrote their files
non-atomically (write_text in place), which is exactly what produces the corrupt
file after a crash/kill/disk-full mid-write.

This generalizes the resilient pattern already used inline by ChannelBuffer and
WorkspaceTrustStore into two shared helpers (coworker/jsonstore.py):

- read_json(): missing/corrupt file -> caller default, moving the bad file aside
  to <name>.corrupt so it is neither lost nor re-hit on the next boot.
- write_json_atomic(): temp sibling + os.replace, atomic on POSIX and Windows.

Every affected store now uses them. Adds tests covering the helpers and each
store's construct-from-corrupt-file path plus a save round-trip.

Related to the WakeStore-specific report in andrewyng#158 (that fix, andrewyng#159, covers only
selfwake.py); this addresses the same failure mode across the rest of the
persistence layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Corrupt JSON state files crash server startup across the whole store layer (not just WakeStore/#158)

1 participant