[BUG] Task tools' per-session lockfile fails with EPERM (`utimensat`) when CLAUDE_CONFIG_DIR is on an SMB/CIFS mount (e.g. Azure Files)
Environment
- Claude Agent SDK (Python) ≥ 0.2.110, bundled CLI ≥ 2.1.142 (still present on current versions)
- Linux container (Azure Container Apps),
CLAUDE_CONFIG_DIRpointed at a volume backed by Azure Files (SMB / CIFS mount) - Headless SDK usage (
bypassPermissions)
Bug
Since the in-session task tool flipped from TodoWrite to the structuredTaskCreate/TaskUpdate/TaskList/TaskGet family (CLI 2.1.142), each
session maintains a lockfile at:
{CLAUDE_CONFIG_DIR}/tasks/<session-id>/.lock.lock
The lock implementation calls utimensat(2) on this file (touch-style
timestamp update). On a CIFS/SMB mount this fails with EPERM — the
Linux CIFS client rejects the timestamp update even though the process
owns the file and the mount is read-write. Task tool calls then error out
for the whole session.
Plain file writes (including the session JSONL transcripts in the same
config dir) work fine on the same mount — it's specifically the
timestamp-update step of the lock protocol that trips.
Repro
- Mount an Azure Files share (or any CIFS mount) and set
CLAUDE_CONFIG_DIR to a directory on it.
- Run any SDK session and let the model call
TaskCreate. - Observe EPERM from
utimensatontasks/<session>/.lock.lock; task
tools unusable for the session.
Minimal isolation without the SDK: touch f && python3 -c "import os; on the CIFS mount reproduces the EPERM for the same class
os.utime('f')"
of mount options.
Workaround we're riding
CLAUDE_CODE_ENABLE_TASKS=0 (the documented back-compat knob) to keepTodoWrite. Works, but it pins us to the legacy tool family and we'd
like to adopt the Task tools.
Suggested fixes (any one would unblock)
- Tolerate
EPERM/ENOTSUPfrom the timestamp-update step of the lock
protocol (fall back to write-based liveness, or treat as advisory), or
- Make the tasks/lock directory location independently configurable
(e.g. CLAUDE_TASKS_DIR) so it can point at local ephemeral disk while
the config dir stays on the share, or
- Use an O_EXCL-create + unlink lock scheme that avoids
utimeentirely.
Related precedent: 2.1.181's changelog fixed Write/Edit producing
0-byte/truncated files on network drives — this is the same substrate
class (SMB semantics), one layer up in the lock protocol.