[Bug] Windows: EPERM race on ~/.acpx/sessions/index.json under --jobs > 1 is misreported as "adapter does not support sessions"

Open
#91 5 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
65/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
javascript, node.js
Domain
cli

Research direction

Start in src/acpx.js, tracing how openSession() handles failures returned by classifyAcpxFailure() and how probeSession() represents transient errors. Check the existing tests for these paths before making a change; the issue does not name specific test files. Done means transient filesystem contention is reported as such, not as unsupported session capability, without changing the optional retry policy.

Written by the indexing model from the issue text.

Description

ready-for-pr

Split out of #70 at the maintainer's invitation, so the effort-off work there can stay scoped. Different root cause, same user-visible string.

Environment: Windows 11, Node v22.19.0, [email protected], [email protected], Codex harness. Spawn patched locally per #43, otherwise nothing reaches a harness on Windows at all.

What happens

A default run (--jobs 4) over 100 transcripts produced three of these:

warn ... acpx codex could not apply invocation-scoped effort=medium:
  EPERM: operation not permitted, rename
  'C:\Users\<user>\.acpx\sessions\.acpx-write.76536.1788153603136.<uuid>.tmp'
  -> 'C:\Users\<user>\.acpx\sessions\index.json'

and then, once, this — which ended the run:

error codex cannot apply invocation-scoped effort=medium
      because its acpx adapter does not support sessions
  upgrade acpx or omit the effort override

The adapter supports sessions perfectly well. The same corpus finished cleanly minutes later.

Why the second message follows from the first

~/.acpx/sessions/index.json is a single shared file that acpx rewrites with the write-tmp-then-rename pattern. POSIX rename replaces an open target atomically; Windows returns EPERM while another handle is open. backpass's default --jobs 4 puts four acpx processes on that one file at once.

From there the chain is entirely inside backpass (src/acpx.js):

  1. openSession() gets a non-zero exit from sessions new and asks classifyAcpxFailure() for a verdict.
  2. classifyAcpxFailure() recognises only AUTH_REQUIRED, did not advertise that model, and ENOENT-shaped text. EPERM: operation not permitted, rename … matches none, so it returns null.
  3. null is the "not classifiable" branch, so openSession() sets err.unsupported = true with "has no session support".
  4. sessionPrompt() sees unsupported and throws the UserError above.

So a transient, load-dependent filesystem race is reported as a permanent capability verdict about the adapter, with repair advice (upgrade acpx) that cannot fix it. That is the bug I would like to see fixed; whether the call is also retried is a separate, optional question.

Differential, with its limitation stated plainly
run EPERM "does not support sessions" outcome
--jobs 4, 100 sessions created 3 yes exit 1
--jobs 1, same repo and corpus 0 no exit 0, proposal written

Caveat I do not want to paper over: the second run reused cached analysis, so it created 21 sessions rather than 100. Concurrency and attempt count both changed. This is consistent with a concurrency race; it is not proof of one. The clean arm would be --jobs 4 over the same 21 sessions, which I have not run.

Suggested direction
  • Treat EPERM / EACCES / EBUSY (and similar transient FS codes) as their own verdict rather than falling through to unsupported. probeSession() already carries a transient: true concept; the create path does not reuse it for these codes.
  • Whatever the retry policy, the message should name a filesystem contention problem, not a missing capability — per VISION's "failure is loud and named", the current text is loud but wrongly named, and sends the user to an upgrade that changes nothing.
  • The shared-index write not being concurrency-safe on Windows looks like an acpx-side concern. Raising it here only because backpass is what drives the concurrency, through a default of --jobs 4. A cheap interim mitigation would be documenting --jobs 1 for Windows users; I would not suggest changing the default on this evidence alone.

Related: #70 (same string, effort-config root cause), #43 (the Windows spawn fix that is a prerequisite for reaching any of this).

Measured on Windows with Claude Code; every quoted line is executed output.

Dominant language
JavaScript
Stars
1.5k
Forks
120
Avg merge
1d 52m
Merged PRs (30d)
28

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from kunchenguid/backpass

All issues in kunchenguid/backpass

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.