Windows flake: withFileLock throws EPERM when the previous holder's lock file is still being deleted

Open Beginner friendly
#2,929 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

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

Research direction

Start with src/core/util/file_lock.js and the Windows failure described in test/core/action-marker-lock.test.js:344. Check how withFileLock handles errors from fs.open(lockPath, 'wx') and how the existing deadline loop retries; add focused coverage by injecting the relevant error code. Done when the transient Windows error is retried and the lock contention test passes.

Written by the indexing model from the issue text.

Description

What happened

On test-windows, test/core/action-marker-lock.test.js:344 ("concurrent removals from two processes both stick") failed because one worker exited 1:

Error: EPERM: operation not permitted, open '...\hypaware\config-control\client-actions.json.lock'
    at async withFileLock (src/core/util/file_lock.js:68:22)
  • Run 42283835049, job 128119418060 (#2928 at 44c35d11, Node 26.13.0 on windows-latest), 2026-11-06T19:55Z.
  • The PR does not touch the lock or the action markers; every other job on that head was green.

Likely cause

withFileLock creates the lock with fs.open(lockPath, 'wx') and retries only on EEXIST. On Windows, while the previous holder's fs.rm of the lock file is still pending, a create of the same name fails with EPERM (access denied on a delete-pending file) rather than EEXIST. The lock then throws instead of waiting, so the caller's operation fails.

Reach

This is not only a test problem. Every withFileLock caller can hit it on Windows under contention between two processes:

  • the client-action marker store (action_reconciler.js);
  • remote credentials (credentials.js);
  • the service token (service_token.js);
  • the grep config migration (grep_migration.js).

The failure is a spurious error before fn runs, so nothing is half-written. The operation is refused, not corrupted.

Possible fix

On win32, treat EPERM (and possibly EACCES) from the wx open like EEXIST inside the existing deadline loop. A test can inject the error code.

🤖 Generated with Claude Code

Dominant language
JavaScript
Stars
11
Forks
0
Avg merge
2h 15m
Merged PRs (30d)
322

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

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 hyparam/hypaware

All issues in hyparam/hypaware

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.