MoonshotAI / MoonshotAI/kimi-code
[Windows] Plugin update fails with EBUSY: managed plugin directory locked by its own running MCP server child process
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
Problem type
Windows file-locking / process-lifecycle bug: the plugin installer cannot remove a managed plugin's directory because that directory is locked by the plugin's own MCP server child process, which kimi-code itself spawned and keeps running during the session.
Error
Error: Failed to install Kimi Datasource: [internal] EBUSY: resource busy or locked, rmdir
'C:\Users\38623\.kimi-code\plugins\managed\kimi-datasource'
Root cause analysis
-
A managed plugin declares an MCP server whose working directory is the plugin directory itself. Example from
~/.kimi-code/plugins/managed/kimi-datasource/kimi.plugin.json:"mcpServers": { "data": { "command": "node", "args": ["./bin/kimi-datasource.mjs"], "cwd": "./" } } -
While a kimi-code session is running, the plugin's MCP server stays alive as a child process. Verified on the affected machine:
kimi.exe (PID 43740) __plugin_run_node ./bin/kimi-datasource.mjsThis process's current working directory is
C:\Users\38623\.kimi-code\plugins\managed\kimi-datasource, and it also holds an open handle onbin/kimi-datasource.mjs. -
On Windows (unlike POSIX), a directory that is any process's working directory — or that contains files with open handles — cannot be removed.
fs.rmdir/rm -rfon it fails withEBUSY: resource busy or locked. -
When kimi-code tries to install/update the plugin, it removes the existing directory without first stopping the plugin's MCP server child process (or without waiting for it to exit), so the
rmdirdeterministically fails with EBUSY. -
This creates a catch-22 for the user:
- Keep the session running → the MCP child process holds the lock → update fails with EBUSY.
- Kill the process/session → the CLI that would perform the update is also gone → update still doesn't happen.
Reproduction
- On Windows, install a managed plugin that runs an MCP server (e.g. Kimi Datasource).
- Start a kimi-code session (the plugin's MCP server child process starts, with cwd inside the plugin directory).
- Trigger a plugin update/reinstall (from
/pluginsor wherever the update is offered). - Observe:
Failed to install ...: [internal] EBUSY: resource busy or locked, rmdir '<plugin dir>'.
Environment
- OS: Windows 11 (10.0.26200.8875), x86_64
- kimi-code version: 0.30.0
- Plugin: kimi-datasource 3.3.0 (managed)
- Install path:
C:\Users\<user>\.kimi-code\plugins\managed\kimi-datasource
Suggested fixes
Any of these would resolve it:
- Stop-then-reinstall: before removing a managed plugin directory, terminate that plugin's MCP server child process(es) and wait for exit (with a timeout + force kill fallback), then
rmdir. - Rename-then-swap (more robust on Windows): rename the old directory to a sibling temp name (rename often works even when the dir is busy), install the new version, and delete the old directory on next startup when nothing holds it.
- Deferred deletion: if
rmdirfails with EBUSY/EPERM, schedule the cleanup for next CLI launch instead of hard-failing the whole install. - Retry with backoff: Windows AV/indexer locks are often transient; retrying
rmdira few times with delay is a common mitigation — though for this specific bug the lock is held by kimi-code's own child for the whole session, so retries alone won't help without fixing the lifecycle ordering.
Note: the cwd: "./" in the plugin manifest makes the plugin directory itself the MCP server's working directory, which guarantees the lock for the entire session. Even without cwd, the running node process keeps an open handle on bin/kimi-datasource.mjs, which blocks removal of that file on Windows too.
Workaround for affected users
Fully exit all kimi-code sessions, then manually delete ~/.kimi-code/plugins/managed/kimi-datasource, then restart kimi-code and reinstall the plugin. (If a stale kimi.exe ... __plugin_run_node process survives, kill it first.)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the managed-plugin update/install path and the MCP child-process lifecycle described in the issue. Reproduce on Windows with a plugin whose MCP server uses the plugin directory as cwd, then trace how the server is stopped before directory removal. Done means the existing managed plugin can be updated during a session without EBUSY, with the process exited before cleanup.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- cli, operating-systems, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100