Ignore removed Time Travel workspaces
Drop queued debounced snapshots when the workspace directory is gone before the timer flushes. This keeps transient delete/rename races from surfacing as Time Travel snapshot errors while preserving normal snapshot failures for existing workspaces.
Alessandro committed
Jul 9, 2026 at 17:26 UTC
1a6d0eb6147edb763370b6d1554e71441f5644a1
2 files changed
+25
plugins/_time_travel/helpers/time_travel.py
+2
@@ -618,6 +618,8 @@ def _flush_debounced_snapshot(workspace_id: str) -> None:
618
619
try:
620
workspace = payload["workspace"]
621
+ if not workspace.real_path.is_dir():
622
+ return
623
TimeTravelService(workspace).snapshot(
624
trigger=str(payload.get("trigger") or "watchdog"),
625
metadata=payload.get("metadata") or {},
tests/test_time_travel.py
+23
@@ -351,6 +351,29 @@ def test_debounced_snapshots_coalesce_to_one_commit(workspace):
351
tt.clear_debounced_snapshots()
352
353
354
+def test_debounced_snapshot_skips_removed_workspace(workspace, monkeypatch):
355
+ root, service = workspace
356
+ errors = []
357
+ monkeypatch.setattr(tt.PrintStyle, "error", lambda message: errors.append(message))
358
+ tt.clear_debounced_snapshots()
359
+ try:
360
+ (root / "file.txt").write_text("one\n", encoding="utf-8")
361
+ tt.schedule_debounced_snapshot(
362
+ service.workspace,
363
+ trigger="watchdog",
364
+ metadata={"source": "watchdog"},
365
+ delay=60,
366
+ )
367
+ shutil.rmtree(root)
368
+
369
+ tt.flush_debounced_snapshots()
370
+
371
+ assert errors == []
372
+ assert not service.workspace.repo_git_path.exists()
373
+ finally:
374
+ tt.clear_debounced_snapshots()
375
+
376
+
377
def test_workspace_resolution_prefers_project_and_rejects_external_paths(monkeypatch: pytest.MonkeyPatch, workspace):
378
root, _service = workspace
379
projects_mod = ModuleType("helpers.projects")