Windows: plugin update fails with "Access is denied (os error 5)" while VS Code is running (Copilot extension holds watcher handles on installed-plugins)
- Dominant language
- Shell
- Stars
- 11.2k
- Forks
- 1.9k
- Avg merge
- 14h 16m
- Merged PRs (30d)
- 6
Description
### Describe the bug
`copilot plugin update` (and the same flow triggered from the GitHub Copilot desktop app) fails on Windows with:
```
Failed to update plugin: Error: Failed to install plugin: Error: Access is denied. (os error 5)
```
The git fetch/checkout of the marketplace clone succeeds every time (the clone under `%LOCALAPPDATA%\copilot\marketplaces\...` ends up at the target commit, working tree clean). The failure happens in the final step that replaces `~\.copilot\installed-plugins\\`.
Root cause (verified with a system-wide handle enumeration via `NtQuerySystemInformation(SystemExtendedHandleInformation)`): **VS Code's Copilot extension holds directory watcher handles** (access mask `0x100081`, i.e. `ReadDirectoryChangesW`-style) on the installed plugin folder itself and its `hooks`, `agents`, and `skills` subdirectories:
```
pid=15064 handle=0x424 access=0x100081 path=\?\C:\Users\\.copilot\installed-plugins\\al-agentic-dev
pid=15064 handle=0x65c access=0x100081 path=...\al-agentic-dev\hooks
pid=15064 handle=0x678 access=0x100081 path=...\al-agentic-dev\agents
pid=15064 handle=0x67c access=0x100081 path=...\al-agentic-dev\skills
```
(pid 15064 = `Code.exe --type=utility --utility-sub-type=node.mojom.NodeService` — the VS Code file-watcher host.)
On Windows, a directory that has an open watcher handle cannot be renamed/replaced, so the installer's folder swap fails with `ERROR_ACCESS_DENIED (5)`. Closing VS Code releases the handles and the identical update command then succeeds immediately (v2.5.0 → v3.0.0 in my case).
This is very confusing for users: restarting the Copilot desktop app doesn't help, and even a reboot doesn't help if VS Code relaunches before the update is retried. The error message gives no hint that another application is holding the folder.
### Affected version
GitHub Copilot CLI 1.0.70 (also reproduced through GitHub Copilot desktop app 1.0.21, which calls the same installer via `plugins.update`)
### Steps to reproduce the behavior
1. On Windows, install a plugin from a marketplace, with the VS Code GitHub Copilot extension active (so it watches `~\.copilot\installed-plugins\...`).
2. With VS Code still running, run `copilot plugin update @` (or click Update in the desktop app's plugin settings).
3. Error: `Failed to install plugin: Error: Access is denied. (os error 5)`. The installed plugin stays at the old version.
4. Close VS Code, run the same command → update succeeds.
### Expected behavior
The update should succeed while VS Code is running — e.g. by copying the new version into place file-by-file instead of renaming/removing the directory root, by retrying with backoff, or by staging to a sibling dir and swapping with `FILE_RENAME_FLAG_POSIX_SEMANTICS`. Failing that, the error message should name the process holding the directory (the Restart Manager API can identify it) so users don't reach for a reboot.
### Additional context
- Operating system: Windows 11 Pro 10.0.26200, x86_64
- Diagnosis details: per-file probes all pass (no file locks, no read-only attributes, ACLs fine — Restart Manager reports nothing because it doesn't surface directory watcher handles); only the rename of the plugin folder root fails. Bisected by rename-probing every subdirectory: only the root and the three watched subdirs are held.
- The plugin in question ships `hooks/`, `agents/`, `skills/` and an `extensions/` canvas extension, but the bug is independent of plugin content — any plugin folder watched by VS Code's Copilot extension will hit it.
Contributor guide
Research direction
Start at the `copilot plugin update` entry point and trace the Windows installer step that replaces the installed plugin directory. Reproduce the failure with VS Code running and its Copilot extension active; done means the update succeeds without closing VS Code, or the error identifies the process holding the directory.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- vscode
- Domain
- cli, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100