Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Share-bucket export fails on a transient Windows file lock because copyFileGuarded has no EBUSY retry

Open
#12,886 0 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
76/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
javascript, node.js
Domain
backend, testing

Research direction

Start with server/lib/fileCore.js and compare its rename retry logic (WIN_RETRY_ATTEMPTS and WIN_RETRY_DELAY_MS) with the read lock handling in jsonIo.js. Add the Windows-only copy retry at copyFileGuarded and deterministic unit tests for transient EBUSY and non-retried ENOENT, reusing the injectable delay. Done means the bounded retry behavior and unchanged handling of other errors and platforms are covered.

Written by the indexing model from the issue text.

Description

area:federation bug effort:medium model:light plan planner:sonnet-5-5

Problem

copyFileGuarded (server/lib/fileCore.js) is a bare copyFile, so a share-bucket export fails outright when Windows momentarily locks the source or destination file (antivirus scan, search indexer). The sibling Windows write paths already tolerate exactly this (WIN_RENAME_LOCK_CODES for rename, WIN_READ_LOCK_CODES in jsonIo.js); the copy does not.

Evidence: one CI failure, Windows shard Windows server unit tests (3/3), on a pull request that touches no sharing code. The same test passed in the next run of the unchanged head, so it is transient, not reproduced:

FAIL services/sharing/integration.test.js > sharing round-trip > names an exported media record by its job id, never by an imported sidecar id
Error: EBUSY: resource busy or locked, copyfile '<runner-temp>\...\images\shared-job.png' -> '<runner-temp>\...\portos-sharing-roundtrip-bucket-…'

The failing call is the exporter's blob copy (server/services/sharing/exporter.js, copyFileGuarded(sourcePath, blobPath)), which is production code on a real Windows install, not a test helper: a just-written image that an indexer is holding makes a share export fail with no retry.

Decision

  1. Retry copyFileGuarded on the transient Windows lock codes (EPERM, EACCES, EBUSY) with the same bounded attempts and backoff the module already uses for rename (WIN_RETRY_ATTEMPTS / WIN_RETRY_DELAY_MS), on win32 only; every other error and platform behaves as today.
  2. Cover it with a unit test that injects a copyFile throwing EBUSY twice and then succeeding (success after retries), and one that throws ENOENT (no retry, original error preserved). No real sleeps: reuse the module's injectable delay.
  3. Do not add a retry inside the sharing exporter or the test; the helper is the shared boundary.

Acceptance criteria

  • A copy that hits EBUSY up to the retry bound succeeds; a persistent lock still throws the original error.
  • Non-lock errors and non-Windows platforms are unchanged.
  • sharing/integration.test.js stays green on the Windows shards across 20 consecutive runs.

Found while shipping #12850; unrelated to its change. Dispatch rationale: model:light — one shared helper with an established pattern to copy; effort:medium because the retry bound and Windows-only gating need care and a deterministic test.

Dominant language
JavaScript
Stars
38
Forks
32
Avg merge
35m
Merged PRs (30d)
993

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 atomantic/PortOS

All issues in atomantic/PortOS

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.