Skip to content

(Claude) Tests that build projects in the system temp dir share one cache database #409

Open

Description

@cboos

Several test files build their project directly under the system temp dir. test/test_tui.py's temp_project_dir fixture, for one, creates it with tempfile.TemporaryDirectory() and builds a CacheManager without a db_path. CacheManager then defaults to get_cache_db_path(project_path.parent). That is <tmp>/claude-code-log-cache.db, one file that every such test, every run and every checkout on the machine shares.

What goes wrong

The shared database outlives the tests and takes whichever schema the last code to open it migrated it to. When a checkout carrying a later migration runs these tests, an older checkout's run then fails on schema it does not know.

This happened on 2026-11-07. A checkout of #390, which adds 016_drop_refresh_pending.sql, opened /tmp/claude-code-log-cache.db and migrated it to 016 at 03:26Z. From then on, main's code (migrations up to 015) failed 24 of test_tui.py's 63 tests, all with:

sqlite3.OperationalError: no such column: refresh_pending

They fail in SessionBrowser.on_mount → load_sessions → CacheManager.get_modified_files. Nothing in the tree under test was wrong. The same tests pass once the temp dir is fresh:

# main's code (88426a39), default temp dir
uv run pytest test/test_tui.py -n0 -p no:cacheprovider -q -m "tui or not tui"
→ 24 failed, 39 passed

# the same tree, a fresh temp dir
TMPDIR=$(mktemp -d -p ~/tmp) uv run pytest test/test_tui.py -n0 -p no:cacheprovider -q -m "tui or not tui"
→ 63 passed

The same stale database also fails just test on main's code: 13 tests in test/test_pagination.py and test_multi_session_rendering in test/test_template_rendering.py, all with IndexError: No item with that key on project_row["refresh_pending"] (CacheManager.get_cached_project_data). In a fresh temp dir the two files pass in full (49 and 11).

A fresh temp dir is not enough under xdist. just test-tui runs with pytest-xdist's default -n auto. With TMPDIR set to an empty directory, every worker's temp projects share one brand-new $TMPDIR/claude-code-log-cache.db, and several workers run its migrations at the same moment. One run gave 4 failures out of 71, all raised in migrations/runner.py's run_migrations from CacheManager.__init__:

sqlite3.IntegrityError: UNIQUE constraint failed: _schema_version.version   (3x)
sqlite3.OperationalError: duplicate column name: combined_linked            (1x)

Migrating that database once first (one test with -n0) and then running the suite against the same TMPDIR gave 4129 passed, 7 skipped for just test. A first run on a fresh CI runner could hit the same race; CI history has not been checked for it.

The shared file also accumulates: it held 1,423 project rows, all /tmp/tmpXXXXXXXX paths, read with SELECT count(*) FROM projects in read-only mode.

Scope

  • Verified: test/test_tui.py (24 failures on the stale database, 4 from the migration race on a fresh one), test/test_pagination.py (13) and test/test_template_rendering.py (1).
  • Not checked: whether other tests do the same. These test files create temp dirs with tempfile.TemporaryDirectory() or mkdtemp(), and any of them that builds a CacheManager or runs a conversion without CLAUDE_CODE_LOG_CACHE_PATH or a db_path would share the same file: test_cache.py, test_tui_expansion.py, test_integration_realistic.py, test_session_scan_characterization.py, test_template_data.py, test_sidechain_agents.py, test_lanes.py, test_project_matching.py, test_combined_transcript_link.py, test_image_paste_ids.py, test_memory_browser.py, test_todowrite_rendering.py, test_webfetch_rendering.py, and the browser files test_query_params_browser.py, test_timeline_browser.py, test_search_browser.py.
  • The stale-schema failure needs a temp dir that outlives a run, so it bites on a developer machine that runs several checkouts, or a branch carrying a new migration, over the same temp dir. The migration race needs only a fresh temp dir and xdist.

Possible fix

test/conftest.py already has isolated_cache_dir / isolated_db_path / isolated_cache_manager, described there as preferred over the older temp_project_dir pattern. Two ways to use that:

  • Move temp_project_dir onto tmp_path and give the cache an explicit path inside it.
  • Have an autouse fixture set CLAUDE_CODE_LOG_CACHE_PATH to a per-test path for every test that does not set its own. That would also cover the files above without touching each one.

🤖 Generated with Claude Code

Activity

  1. added
    bugSomething isn't working
    on Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions