Skip to content

Fix/autoreload watcher race#10226

Open
Felipenguim wants to merge 5 commits into
marimo-team:mainfrom
Felipenguim:fix/autoreload-watcher-race
Open

Fix/autoreload watcher race#10226
Felipenguim wants to merge 5 commits into
marimo-team:mainfrom
Felipenguim:fix/autoreload-watcher-race

Conversation

@Felipenguim

Copy link
Copy Markdown
Contributor

📝 Summary

Closes #10191
Related: #10225 (found while validating this fix)

The bug

marimo's module autoreload has two independent consumers sharing the same ModuleReloader state (modules_mtimes / stale_modules in marimo/_runtime/reload/autoreload.py). Both call ModuleReloader.check(), which one sees a file's mtime change first "consumes" it for both, creating a race conditioncell_scope() reloads the module correctly, but the watcher never gets to run its transitive dependency analysis for that change. like the self-import cycle in #10191 — never get marked stale.

The fix

ModuleReloader gets a second, independent mtime baseline (watcher_modules_mtimes) and a check_for_watcher() method, used only by ModuleWatcher. This lets the watcher detect "did this file change since I last checked" on its own terms, regardless of whether cell_scope() already reloaded it in the meantime. _check_modules now calls both check() (kept — cell_uses_stale_modules/flag_if_imports_stale still rely on it being populated) and check_for_watcher() (used for the transitive-dependency computation).

Tests

  • test_reload_self_import_cycle: the scenario from the issue.
  • test_reload_self_import_cycle_race_with_other_cell: same setup, but forces an unrelated cell to rerun right after the file changes and before the watcher's next poll. Specifically exercises the race.

Note on #10225

While testing this manually against my own editable install, I ran into a separate, pre-existing bug: modulefinder crashes on marimo's own namespace packages, which silently breaks dependency detection, but only in dev setup, not for regular users. It briefly made this fix look broken even though it wasn't, but when I tested it with the a built app, it worked.

📋 Pre-Review Checklist

  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • Video or media evidence is provided for any visual changes (optional).

✅ Merge Checklist

  • I have read the contributor guidelines.
  • Documentation has been updated where applicable, including docstrings for API changes.
  • Tests have been added for the changes made.

@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jul 19, 2026 4:33pm

Request Review

continue
pymtime = module_mtime.mtime

existing_mtime = self.watcher_modules_mtimes.get(modname)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This separate map never gets cleared when a module name is rebound to another __file__. check() explicitly drops modules_mtimes on that path but leaves this old baseline behind, so a replacement file with an older mtime and subsequent edits stay invisible until its timestamp passes the previous file’s.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

52527f2
Now in the functioncheck() the watcher_modules_mtimes also gets cleared to deal with modules being rebound

f3dafec
A new test to ensure it

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.

Cyclical notebook import from another file don't auto-reload

2 participants