[BUG] Task tools always fail with EPERM (utimensat on lockfile) when CLAUDE_CONFIG_DIR is on Cloud Storage FUSE (Cloud Run + Agent SDK)

Resolved 💬 1 comment Opened Jun 4, 2026 by matzkoh Closed Jul 8, 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?

When Claude Code runs headlessly via the Agent SDK with CLAUDE_CONFIG_DIR located on a Cloud Storage FUSE (gcsfuse) volume — the standard way to persist session state for an SDK service on Google Cloud Run — every TaskCreate / TaskUpdate call fails with:

EPERM: operation not permitted, utimensat '<CLAUDE_CONFIG_DIR>/tasks/<session-id>/.lock.lock'

Root cause (verified against the v2.1.162 binary): the task store under $CLAUDE_CONFIG_DIR/tasks/<session>/ serializes writes with a lockfile (bundled proper-lockfile). proper-lockfile updates the lock's mtime via utimens/utimensat for staleness detection. gcsfuse does not support setting arbitrary mtimes through setattr (a long-standing, documented limitation — GoogleCloudPlatform/gcsfuse#33), so lock acquisition always throws EPERM and the whole tool call fails.

Consequences in this environment:

  • Since v2.1.142 the Task tools replaced TodoWrite as the default session checklist (tools reference), so task tracking is now entirely broken for SDK deployments that persist CLAUDE_CONFIG_DIR on gcsfuse.
  • The periodic task_reminder keeps nudging the model to call TaskCreate, the call fails with EPERM, and the loop repeats — wasted calls and confusing error chips for end users.
  • There is no escape hatch: the tasks directory is hard-derived from CLAUDE_CONFIG_DIR (no separate override), and the lock's mtime touch cannot be disabled.

What Should Happen?

Task tools should work — or degrade gracefully — on filesystems that don't support utimensat. Any of these would solve it:

  1. Graceful degradation: treat the mtime-touch failure (EPERM/ENOSYS) as non-fatal and fall back to lock acquisition without staleness touching, rather than failing the entire tool call.
  2. Configurable task store location (e.g., CLAUDE_CODE_TASKS_DIR): allow pointing the task store at a local writable filesystem while sessions remain on the FUSE mount.
  3. Automatic fallback: if the task store is unusable, disable the Task tools for the session and re-enable the in-memory TodoWrite instead of exposing tools that can never succeed.

Error Messages/Logs

# tool_result (is_error: true) returned for every TaskCreate call, e.g.:
EPERM: operation not permitted, utimensat '/app/.claude-admin-help-assistant/user_xxx/tasks/04fc8dea-5320-4ec5-a451-356472416497/.lock.lock'

Session transcripts show consecutive TaskCreate attempts all failing identically.

Steps to Reproduce

  1. Deploy a service to Cloud Run (gen2) with a Cloud Storage volume mount:

``
--add-volume=name=claude-config,type=cloud-storage,bucket=<bucket>
--add-volume-mount=volume=claude-config,mount-path=/app/.claude-config
``

  1. Call the Agent SDK with the config dir on that mount (claude-code CLI ≥ 2.1.142, so Task tools are enabled by default):

```ts
import { query } from '@anthropic-ai/claude-agent-sdk'

query({
options: {
env: { CLAUDE_CONFIG_DIR: '/app/.claude-config/some-user' },
// ...
},
})
```

  1. Send any prompt that makes the model track multi-step progress (or just wait for the task_reminder to nudge it into calling TaskCreate).
  2. Every TaskCreate / TaskUpdate returns the EPERM: operation not permitted, utimensat ... error above.

Minimal repro of the underlying FS limitation without Cloud Run: mount any bucket with gcsfuse and touch an existing file inside the mount → touch: setting times of '...': Operation not permitted.

Current workaround: set CLAUDE_CODE_ENABLE_TASKS=0 to re-enable the in-memory TodoWrite (which never touches the filesystem, so it is unaffected) — at the cost of relying on a deprecated tool.

Claude Model

Sonnet (default)

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.141 (before v2.1.142, the default session checklist was the in-memory TodoWrite, which is unaffected by the gcsfuse limitation; the Task tools themselves have never worked on gcsfuse)

Claude Code Version

2.1.162 (Claude Code)

Platform

Anthropic API

Operating System

Other Linux

Terminal/Shell

Non-interactive/CI environment

Additional Information

  • Environment: Google Cloud Run (gen2) + Cloud Storage FUSE volume mount; Claude Code spawned headlessly by @anthropic-ai/claude-agent-sdk (query()), one process per request with resume.
  • gcsfuse limitation reference: https://github.com/GoogleCloudPlatform/gcsfuse/issues/33 (arbitrary mtime via setattr unsupported; no mount option exists to allow it).
  • This deployment shape (serverless + FUSE-mounted bucket for CLAUDE_CONFIG_DIR persistence across instances) is common for Agent SDK services, so any such deployment on a current CLI hits this.
  • Related but distinct lock-mechanism reports: #22166 (stale history.jsonl.lock freeze), #22169 (tasks/.lock not released). Neither covers the unsupported-utimensat failure mode.

View original on GitHub ↗

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