Skip to content

fix(task-store): tolerate Windows EPERM/EACCES rename during atomic save#43

Merged
win4r merged 1 commit intowin4r:masterfrom
leonastar215gh:fix/windows-task-store-rename-eperm-core
Mar 29, 2026
Merged

fix(task-store): tolerate Windows EPERM/EACCES rename during atomic save#43
win4r merged 1 commit intowin4r:masterfrom
leonastar215gh:fix/windows-task-store-rename-eperm-core

Conversation

@leonastar215gh
Copy link
Copy Markdown
Contributor

fix(task-store): tolerate intermittent Windows EPERM/EACCES rename failures when saving tasks


Summary

On Windows (especially in corporate environments with antivirus / file indexers / DLP), atomic rename(tmp -> target) can intermittently fail with EPERM/EACCES. When this happens inside the A2A gateway task store, the durable task state cannot be persisted and long-running A2A flows (async task mode, --non-blocking --wait / tasks/get) become unreliable.

This PR makes FileTaskStore.save() more resilient:

  • keep atomic rename as the fast/primary path
  • when rename fails with EPERM/EACCES, retry a few times with small backoff
  • if it still fails, fall back to a best-effort non-atomic overwrite write, and clean up the tmp file

This changes a hard failure into a recoverable path so polling can continue.


Why this matters

A2A async task mode relies on being able to persist incremental task states. A single failure to write the task JSON can break polling and make agent-to-agent messaging appear flaky.


Repro (Windows)

  1. Run A2A Gateway on Windows.
  2. Trigger async tasks at a moderate rate (or concurrently), especially on a machine with active antivirus/indexing.
  3. This is easiest to reproduce when running multiple OpenClaw profiles on the same machine/user (shared task store directory), but the underlying file-lock race can also happen in single-gateway setups.
  4. Observe intermittent:
EPERM: operation not permitted, rename '<task>.json.<pid>.<ts>.tmp' -> '<task>.json'

Fix

src/task-store.ts:

  • wrap rename(tmp, target) in a try/catch
  • only handle EPERM/EACCES
  • short backoff retries
  • fallback to writeFile(target, payload) + best-effort tmp cleanup

Deployment / config note (recommended)

When running multiple OpenClaw profiles on the same Windows user, do not share the default task store directory.

Recommend configuring per-profile:

  • plugins.entries.a2a-gateway.config.storage.tasksDir

Example:

{
  "plugins": {
    "entries": {
      "a2a-gateway": {
        "config": {
          "storage": {
            "tasksDir": "C:/Users/<user>/.openclaw-<profile>/a2a-tasks"
          }
        }
      }
    }
  }
}

This reduces cross-profile collisions and further improves stability.


Testing

  • npx tsc --noEmit
  • npm test

CI already runs on ubuntu; the change is isolated and should be platform-safe.

@win4r win4r merged commit 2d95551 into win4r:master Mar 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants