[BUG] Cowork scheduled task creation fails: "path moved between validation and open" — TOCTOU guard false-positives on FSLogix profile containers

Status Open
Maintainer reply None cached
Activity 1 comment · opened Jul 31, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Creating a scheduled task in Cowork fails 100% of the time with path moved between validation and open. The SKILL.md file is written to disk correctly and persists, but registration fails, so list_scheduled_tasks returns nothing while a valid file sits on disk.

The same error message also appears as a non-fatal warning on every host-side file read on the affected machines, against files that read successfully in the same session — the underlying time-of-check-to-time-of-use guard is false-positiving across the machine, and scheduled-task creation is simply the one code path that treats the condition as fatal. A controlled A/B (details in Additional Information) shows the trigger is an attached FSLogix profile container: on the same binary with no container attached, creation succeeds and the guard string appears zero times in the log's entire history.

(The warn variant recurs at 12:32, 14:08, 14:42, 15:03, 15:12, 15:14 and 15:17 within a single session. There is no fs.link(), EXDEV, EPERM or EACCES anywhere in the stack — this is an application-level assertion, not an OS error.)

What Should Happen?

The scheduled task should be created and registered. Where the path guard cannot verify path identity, it should either surface the actual values it compared or degrade to a warning as it already does elsewhere in the app.

Error Messages/Logs

[error] [ScheduledTasksMcpServer] Failed to create scheduled task: path moved between validation and open
  Error: path moved between validation and open
    at RSe (...app.asar\.vite\build\index.chunk-D4J9UP7v.js:2105:2195)
    at async Object.YEt [as writeScheduledTaskFile] (...index.chunk-D4J9UP7v.js:2105:1566)
    at async O (...index.chunk-D13ifZ1g.js:1:3545)
    at async nne.executeToolHandler (...index.chunk-41sTXhtI.js:118:45595)

Non-fatal variant, different function, on files that were read successfully:

12:32:04 [warn] _readLocalHostFile: path moved between validation and open:
  C:\Users\<user>\Documents\<connected folder>\redacted.md
14:42:05 [warn] _readLocalHostFile: path moved between validation and open:
  ...\LocalCache\Roaming\Claude\local-agent-mode-sessions\...\outputs\redacted.html
15:03:29 [warn] _readLocalHostFile: path moved between validation and open:
  C:\Users\<user>\Documents\<connected folder>\redacted.md

Steps to Reproduce

  1. Windows Server 2025 session host (Citrix DaaS, non-persistent) with FSLogix profile and ODFC containers attached — the standard Citrix/AVD profile configuration. Nested virtualization is enabled and Cowork itself runs normally.
  2. In Cowork, call create_scheduled_task with any taskId, prompt and cronExpression.
  3. Fails immediately with the error above.
  4. <profile>\Claude\Scheduled\<taskId>\SKILL.md exists on disk and is correctly formed.
  5. list_scheduled_tasks returns nothing. update_scheduled_task on that taskId returns "not found", so the registry does not enumerate disk.

Reproduced nine times across three task IDs, on two machines with the same build. Also reproduces with a prompt consisting only of Say hello., so prompt content is not a factor.

Control (same binary, no FSLogix container attached): on the same master image under a local profile — FSLogix filter driver installed but idle, no redirections.xml applied — create_scheduled_task succeeds end-to-end, and main.log contains zero occurrences of the guard string across its entire history.

Claude Model

None

Is this a regression?

I don't know

Last Working Version

Unknown — these are the first scheduled-task attempts on these machines

Claude Code Version

Claude Desktop 1.24012.9.0 (x64, MSIX from claude.ai/download) — Cowork/Desktop issue, not the standalone CLI

Platform

Other

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

This is a different guard from the existing reports

Several closed issues share the symptom but not the mechanism:

  • #67930 and #56001 report Invalid file path: path traversal detected from function Lce — a traversal-pattern check false-positiving on the \\ prefix of a UNC-redirected Documents folder.
  • #46082 reports UNKNOWN: ... link 'x' -> 'y' — an fs.link() call crossing the MSIX virtualization boundary.
  • #43197 reports cross-device hard-link failure when Documents is on a non-C: volume.

This report is neither. The message is path moved between validation and open, the function is RSe, and it is reached via writeScheduledTaskFile. Documents is not redirected on the affected machinesUser Shell Folders\Personal reads a plain local path and is not a reparse point — so the UNC explanation does not apply here either.

Taken together these look like a family of path-validation defects rather than four unrelated bugs. All four issues above are closed and none appear to be fixed.

Eliminated locally

In case it saves anyone the afternoon it cost us:

| Hypothesis | Result |
|---|---|
| EDR / real-time AV quarantine | No. Nothing is deleted; the file survives an app restart. Artifact files write cleanly to the same directory tree. |
| OneDrive Known Folder Move | No. No OneDrive directory in the profile. |
| GPO folder redirection on Documents | No. Local path, not a reparse point. |
| fs.link() across the MSIX boundary (#46082) | No. Absent from the stack trace. |
| Unstable file identity on the container volume | No. File IDs stable across six consecutive queries, both inside the container and on a plain local path. |
| Orphaned task directories | No. Reproduced against a verified-empty Scheduled\ directory. |
| Stale in-memory index | No. Reproduced after a full client restart. |
| Filesystem permissions | No. The process writes the target file successfully. |
| Prompt content or length | No. Reproduced with a three-word prompt. |
| Lexical vs canonical path mismatch across a reparse boundary | No. At the failing path there is no reparse point on it or any parent, it resolves to the same volume as C:\Windows, and GetFinalPathNameByHandle returns NT and DOS paths that both match the lexical path exactly. |
| Broken or half-completed MSIX registration | No. Provisioned machine-wide via Add-AppxProvisionedPackage per Anthropic's deployment guidance, and registered for the running user with Status: Ok. AppXSvc, InstallService and StateRepository all running. |
| VDI without nested virtualization (unsupported per docs) | Not applicable. Nested virtualization is enabled at the hypervisor level and Cowork's VM starts and runs normally. |
| Profile-path casing or 8.3 short-name mismatch | No. %USERPROFILE% matches on-disk casing under ordinal comparison, and every component of both affected paths matches its typed casing exactly. |

Controlled reproduction of the non-fatal variant

The warn-level variant is deterministic, not sporadic. Triggering a host-side file render of a specific file produced the corresponding warning in main.log in the same second (16:22:04), naming that exact file. Every host-side file access observed trips the guard — file-card renders, artifact creation reading its source HTML, host-side file reads — with two log entries per access. Reads proceed despite the warning; only writeScheduledTaskFile escalates the same condition to a hard failure.

A unifying observation

Every path that trips the guard sits under the user profile: the connected workspace folder (...\Documents\...), the scheduled-task store (...\Claude\Scheduled\), and the app's own virtualized data directory. On this estate the entire profile is backed by an FSLogix profile container — filter-driver virtualization with no reparse points on the affected paths, and user-mode canonicalisation that externally tests clean (stable file IDs, GetFinalPathNameByHandle NT and DOS output matching the lexical path).

One estate-specific detail that may matter: the FSLogix redirections.xml excludes LocalCache\Roaming\Claude\vm_bundles from the container (to keep Cowork VM images out of the profile VHDX), which FSLogix implements as a directory junction inside the app's own data tree — a sibling of local-agent-mode-sessions. None of the guard-tripping paths pass through that junction, but if the guard canonicalises directory roots rather than only leaf paths, a junction inside the tree could be what it is reacting to. Note also that FSLogix special-cases Packages\*\LocalCache generally (contents discarded at sign-out by design), so there is more than one FSLogix×MSIX mechanism operating on the app's data tree.

Update — first discriminating test complete (31 July). On the same build (1.24012.9.0), same master image, under a local profile with no FSLogix container attached (the FSLogix filter driver is installed machine-wide but idle for that user; no redirections.xml applied), create_scheduled_task succeeds end-to-end: validation, SKILL.md write, and scheduler registration all complete, task enabled with a next-run time.

The log half is equally clean: main.log on that control machine contains zero occurrences of "path moved between validation and open" across its entire history — which includes an earlier full Cowork session on 28 July and a deliberate host-side read probe during this test. On the affected machines, the same string is logged on every host-side file access.

So the guard is completely silent when no container is attached, and fires universally when one is. Same binary, same image. The failure requires the FSLogix profile-container stack to be active, not merely installed.

Remaining test: a session-host profile with the vm_bundles redirect removed, to separate "attached container generally" from "the junction inside the app data tree specifically".

A guard comparing an identity value that the filter-driver stack answers inconsistently between path-based and handle-based queries would produce exactly this signature: deterministic, profile-wide, and invisible to every external test. We cannot confirm that from outside the application — it needs someone who can see what the function RSe actually compares between "validation" and "open".

The deployment is healthy

Worth stating plainly, because it is the point of the list above: this is a correctly deployed, supported installation on a machine with no detectable filesystem anomaly. The MSIX is provisioned machine-wide and registered per-user with Status: Ok. Paths resolve to a single namespace on a single volume with no reparse points. File identity is stable. Nothing in the endpoint stack is interfering.

No environmental defect was found — every candidate fault was tested and eliminated. The environmental condition was then isolated by A/B instead: an attached FSLogix container. The defect remains application-side — a guard that rejects a path it has just successfully written to, and reports nothing about why — but it manifests only when frxdrv has a container attached.

Note that MSIX package virtualization is exonerated as a sole cause: the control machine runs the identical MSIX package and the guard is silent there. Whatever the guard compares between "validation" and "open" must be answered differently only when the FSLogix filter has an attached container in the path. We cannot measure that from outside the application.

Requests

  1. Make the guard report what changed. path moved between validation and open names no path, no identity value and no OS error. Emitting the before/after values it compared would make this diagnosable in minutes. As it stands it is unactionable from outside the application.
  2. Check the guard against FSLogix specifically — the trigger is proven, not suspected. Controlled A/B on the same binary: container attached → fires on every host-side access and fatally on task creation; container not attached → zero occurrences in the log's entire history. FSLogix profile containers are standard across Citrix and AVD estates, so the affected population is plausibly most enterprise VDI users of Cowork.
  3. Don't fail hard where the same condition is advisory elsewhere. writeScheduledTaskFile treats it as fatal; _readLocalHostFile warns and proceeds successfully.
  4. Consider a directory rescan fallback when the task registry is empty but valid SKILL.md files exist on disk. That alone would make this whole class of failure self-healing.
  5. Consider %LOCALAPPDATA% for task storage, as suggested in #67930. It would sidestep the UNC-redirection members of this bug family — though note it would not by itself fix this report, since on FSLogix estates %LOCALAPPDATA% lives inside the container too. The guard fix (requests 1–3) is the one that matters here.

Happy to run a diagnostic build or any targeted test — the reproduction is reliable and takes seconds.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗