[BUG] CronCreate: fs.mkdirSync(path) does not have the { recursive: true } option, and does not catch EEXIST
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?
Told Claude (in a VS Code session) to create a scheduled daily task. This is the output:
Claude:
The durable option is hitting a persistent bug in this environment (it's failing to write to .claude/scheduled_tasks.json even though the directory already exists — likely a tool bug, not something on my end). Let me try session-only as a fallback and explain the tradeoff.
CronCreate
IN
{
"cron": "47 15 *",
"recurring": true,
"durable": false,
"prompt": "prompt details."
}
OUT
Scheduled recurring job job_id (Every day at 3:47 PM). Session-only (not written to disk, dies when Claude exits). Auto-expires after 7 days. Use CronDelete to cancel sooner.
The job is scheduled (ID job_id, daily at 3:47 PM), but only in session-only mode — the durable option (which would survive across sessions/restarts) is hitting a genuine bug in this environment writing to .claude/scheduled_tasks.json, even though that directory already exists.
Two things you should know about this:
Session-only limitation: this job only fires while this Claude Code session stays open. If you close the session or it ends, the job is gone and won't resume — you'd need to ask me to reschedule it next time you start a session.
7-day auto-expiry: even if the session stays open, the scheduler auto-deletes recurring jobs after 7 days as a safety bound. I'll flag it again when it's about to lapse, but you may want to just ask me to re-run this daily review manually going forward, or re-create the schedule each time you start a new session — whichever is easier given the durable path isn't working right now.
Want me to try the durable path again later (in case it's transient), or are you fine proceeding with the session-only schedule for now?
User:
"What could be causing the issue with the durable path?"
Claude:
Based on the error signature — EEXIST: file already exists, mkdir '...\.claude' — this looks like a bug in the scheduler's write path, not anything on your end. Here's my best read of it:
Most likely cause: the durable-write code probably does something like fs.mkdirSync(path) without the { recursive: true } option, and without catching EEXIST. That call throws whenever the target directory already exists — it's only safe to call on a path that doesn't exist yet. The implementation was likely written assuming .claude/ wouldn't already be there for a first-time scheduled task.
Why it hits this repo specifically: this project's .claude/ directory is not empty or newly created — it already holds settings.local.json, the skills directory, and the memory system. So the very first attempt to persist a scheduled task here hits a directory that's already populated for unrelated reasons, and the mkdir call fails instead of just proceeding to write the file inside it.
This would affect any project with pre-existing .claude/ contents, not something specific to what we did — a repo with a totally fresh .claude/ folder (or none at all) probably wouldn't trigger it, since the first mkdir would succeed normally.
It's a tool-side bug worth reporting rather than something retriable on my end — retrying the identical call three times gave the identical error, which rules out a transient race condition. I'd suggest sticking with the session-only schedule for now, and I can retry the durable path periodically in case it gets patched.
User response: "Who should it be reported to, Anthropic or internal IT"
Claude: This should go to Anthropic, not internal IT — CronCreate is part of Claude Code's built-in tooling, so the bug lives in Anthropic's code, not anything your org's IT team deploys or controls. Internal IT wouldn't be able to fix it even if they wanted to.
The official channel is: https://github.com/anthropics/claude-code/issues
Worth including in the report: the exact error (EEXIST: file already exists, mkdir '...\.claude'), that it happened on CronCreate with durable: true, and that the .claude/ directory already existed with other content (skills, memory, settings) before the first scheduled-task attempt — that's likely the reproducing condition.
What Should Happen?
The durable option should be allowed to write to .claude/scheduled_tasks.json
Error Messages/Logs
CronCreate
IN
{
"cron": "47 15 * * *",
"recurring": true,
"durable": true,
"prompt": "prompt details"
}
OUT
EEXIST: file already exists, mkdir 'C:\Users\...\github\datatech-mcp\.claude'
Steps to Reproduce
Environment
Claude Code version: 2.1.212
OS: Windows 11 Enterprise (build 10.0.26100)
Working directory: a git repo whose .claude/ directory already existed before the first scheduled-task attempt, containing pre-existing content — settings.local.json, a skills/ subdirectory, and a memory/ subdirectory (all unrelated to task scheduling).
Steps to reproduce:
- In a project where .claude/ already exists (with or without prior content — the key variable is that the directory itself is present), invoke the cron/scheduling tool to create a durable recurring job, e.g.:
CronCreate({
cron: "47 15 *",
recurring: true,
durable: true,
prompt: "<any prompt text>"
})
- Observe the result.
Expected behavior: Job is created and persisted to .claude/scheduled_tasks.json; tool returns a job ID.
Actual behavior: The call fails immediately with:
EEXIST: file already exists, mkdir 'C:\Users\hvahed\OneDrive - Ninety One\Desktop\github\datatech-mcp\.claude'
No job is created. This is fully deterministic — retried 3 times with identical cron/durable/recurring values (only the prompt text varied slightly between attempts) and got the identical error every time, ruling out a transient race condition.
Workaround confirmed:
The identical call with durable: false succeeds immediately and returns a valid job ID — so the bug is isolated specifically to the durable-persistence write path (likely an fs.mkdirSync() call on the .claude directory made without { recursive: true } and without catching EEXIST), not the scheduling logic itself.
Suggested isolation step for the Anthropic team (not verified on my end — worth them checking): test the same durable: true call in a fresh project directory where .claude/ does not exist at all yet. If that succeeds, it confirms the bug only triggers when .claude/ is already present — which will be the common case for any actively-used project (skills, memory, settings all live there), making this a fairly high-impact bug rather than an edge case.
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.212
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_