fix(state): log disk state files that fail to load instead of ignoring them

GA
4d ago
+135-2

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Description

StateManagerDisk.load_state() caught every exception and returned None, so an existing state file that could not be loaded was handled like a missing one. get_state() started from a fresh state and the next write replaced the file, and nothing was logged.

This PR keeps the return value (still None, so the app keeps working from a fresh state, as the redis manager does on a mismatch) but makes the failure visible:

  • File that cannot be read or unpickled (bad pickle bytes, truncated or empty file, a pickle referencing a missing module, IO errors): a warning that names the token and file path, with the traceback.
  • Stored schema no longer matches the state class (StateSchemaMismatchError with no chained cause): a debug record. This is an expected reset after editing a state class in dev, and a warning here would fire for every stale substate after each edit.
  • Missing file: unchanged, no log.

BaseState._deserialize also raises StateSchemaMismatchError for unpickling failures, but chains the original error, so a mismatch counts as an expected reset only when it has no chained cause.

I kept this to logging and didn't add a new exception or quarantine the file, because the issue doesn't settle the recovery behavior. If you'd prefer to raise, or to move the unreadable file aside before it gets overwritten, I can change it.

Closes #7167

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Testing

New tests in tests/units/istate/manager/test_disk.py. All of them fail on main:

  • missing file: load_state returns None and logs nothing
  • unreadable file (b"not-a-pickle" and an empty file for both a plain StateToken and a BaseStateToken, plus a pickle that references a missing module): one WARNING that names the token and path and carries exc_info, and get_state still returns a fresh state
  • stale schema (a valid pickle whose stored schema doesn't match): one DEBUG record, no warning, and get_state returns defaults

Commands run:

  • uv run pytest tests/units/istate/manager: 75 passed
  • uv run pytest tests/units --cov --no-cov-on-fail --cov-report=: the only 3 failures also fail on main in my environment (two dataeditor tests need node, one reflex_bench HMR port test)
  • uv run pre-commit run --files <changed files> (ruff format/check, codespell, pyright, ty): all pass

🤖 Opened with Superhuman, an open-source contribution agent.