Skip to content

Fix watch-mode imports map race#1261

Open
eggrollofchaos wants to merge 1 commit into
CodeGraphContext:mainfrom
eggrollofchaos:fix/imports-map-watch-race
Open

Fix watch-mode imports map race#1261
eggrollofchaos wants to merge 1 commit into
CodeGraphContext:mainfrom
eggrollofchaos:fix/imports-map-watch-race

Conversation

@eggrollofchaos

Copy link
Copy Markdown

Summary

  • Snapshot imports_map.items() before the language-specific call-resolution filter iterates it.
  • Add a regression test that mutates the same imports map from another thread while call resolution is reading it.

Why

This is a read/write race on shared mutable state.

Watch mode can schedule overlapping debounce handlers via threading.Timer. Those handlers share self.imports_map: one path may rebuild or update the map while another path is resolving calls and filtering imports by language.

Before this change, _get_lang_imports iterated the live dictionary:

for name, paths in imports_map.items():

If another handler changes the dictionary size during that loop, the reader raises:

RuntimeError: dictionary changed size during iteration

Because the exception is raised in the timer thread, it does not fail the watcher process. Unless stderr is being monitored, the process can continue running while the incremental update that hit the race is silently dropped. The watcher keeps logging Monitoring for file changes, the graph drifts out of sync, and queries can return stale results until a manual cgc index --force.

The race can be triggered when edits land close together under typical watch-mode workload such as save-all, branch switch, or format-on-save. Observed on an actively-edited repo.

Fix

The reader now snapshots the dictionary items before filtering:

for name, paths in list(imports_map.items()):

This matches the existing writer-side pattern that snapshots keys before mutating the same map. It keeps the change focused on the crash without changing the broader watch scheduling behavior.

Related watch-mode scheduling context: #792.

Test plan

  • python -m pytest tests/unit/tools/test_imports_map_race.py -q
  • python -m pytest tests/unit/tools/test_imports_map_race.py tests/unit/tools/test_calls_resolution_tiers.py tests/unit/tools/test_python_call_resolution_patterns.py -q
  • ruff check src/codegraphcontext/tools/indexing/resolution/calls.py tests/unit/tools/test_imports_map_race.py
  • black --check --target-version py312 tests/unit/tools/test_imports_map_race.py

Snapshot the shared imports map before building the per-language import view so concurrent watch-mode updates cannot resize the dictionary during iteration.\n\nAdd a regression test that mutates the same map from another thread while the import filter is reading it.
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

@eggrollofchaos is attempting to deploy a commit to the shashankss1205's projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog tasks

Development

Successfully merging this pull request may close these issues.

1 participant