Skip to content

fix(cli): stop download tmp cleanup racing the write stream open#2722

Open
vanceingalls wants to merge 1 commit into
mainfrom
07-21-fix_cli_download_tmp_cleanup_race
Open

fix(cli): stop download tmp cleanup racing the write stream open#2722
vanceingalls wants to merge 1 commit into
mainfrom
07-21-fix_cli_download_tmp_cleanup_race

Conversation

@vanceingalls

Copy link
Copy Markdown
Collaborator

Summary

downloadFile had two independent cleanup+reject paths racing each other on failure:

  1. request.on("error") → unlink .tmp + reject
  2. pipeline(res, file).catch → unlink .tmp + reject

createWriteStream(tmp) opens asynchronously — on a timeout, path 1 can unlink and reject before the file even exists; the stream's open then creates .tmp after cleanup already ran. In CI this flaked download.test.ts > "rejects an idle response and removes the partial file" (expected true to be false — surfaced on PR #2681's Test job, unrelated to that PR's diff); in the wild it strands partial .tmp files in the model cache dir.

Fix

Once the 200 branch hands the response to pipeline(), the pipeline's catch owns cleanup and rejection — it settles only after the write stream has closed, so the .tmp file provably exists (or never will) when it unlinks. The request error handler stands down in that window, but stashes its error so the precise failure message (e.g. Download timed out after 30000ms) survives — destroying the request can otherwise reject the pipeline with a generic premature-close.

Pre-200 failures (connection refused, redirect errors) keep the original request-error path — no pipeline exists to own cleanup there.

Test plan

  • download.test.ts 10/10 consecutive passes (was intermittent)
  • tsc --noEmit clean
  • oxlint + oxfmt --check clean

Pre-existing since #2415 — not introduced by any open PR; fixing it deflakes every PR's Test job.

🤖 Generated with Claude Code

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.

1 participant