Skip to content

fix(release): stop npm read lag from failing publishes - #498

Merged
wyattjoh merged 1 commit into
mainfrom
claude/publish-resilience-de8wq7
Sep 25, 2026
Merged

wyattjoh merged 1 commit into
mainfrom
claude/publish-resilience-de8wq7

Conversation

@wyattjoh

Copy link
Copy Markdown
Contributor

Requested by Wyatt · project thread

Before: the canary npm publish failed on three of the last five pushes to main (ad60f44, eeb86c5, 5a5a5c9). Every platform package published fine, but the releaser then gave up after 120s waiting to see them, and a re-run failed with npm's "You cannot publish over the previously published versions".

After: the releaser sees a fresh publish right away, treats "already published" as done, and a re-run picks up where the failed attempt stopped.

Both failures come from the same thing. npm view fetches the full packument, which the registry CDN and npm's own local cache hold for five minutes (cache-control: public, max-age=300, cf-cache-status: HIT). The pre-publish check caches the packument without the new version, so every poll in the 120s window reads that stale copy. On the eeb86c5 re-run, the pre-check still read win32-arm64 as missing though attempt 1 had published it, so npm rejected the second publish.

How:

  • isPublished now reads the per-version document (registry.npmjs.org/<name>/<version>), which is not CDN-cached (cf-cache-status: DYNAMIC), and retries 429, 5xx and network errors. check-release.ts and snapshot.ts use the same function and get the fix too.
  • publish treats npm's publish-conflict rejection as success.
  • publishDependenciesBeforePackage uses Promise.allSettled, so one failure no longer exits while other npm publish uploads are still running (the logs show them being killed as orphans, and a killed upload can still land). All failures are reported together and the wrapper is skipped.
  • The availability wait is now five minutes, polling every 5s, as headroom. With the uncached endpoint it should normally pass on the first poll.

No changes to .github/workflows/release.yml or .changeset/config.json, so this does not overlap with #496. Scripts-only change, so no changeset.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PV2ZJ8dVTShiA3PSCGjCYm


Generated by Claude Code

The canary publish job has failed three times since 2026-09-16, all on
registry read-after-write lag:

- ad60f44, 5a5a5c9: every platform package published, then the wait
  for them timed out after 120s. `npm view` fetches the full packument,
  which the registry CDN and npm's own cache hold for five minutes
  (`cache-control: max-age=300`), so polling kept reading the copy
  cached by the pre-publish check.
- eeb86c5 (re-run): the pre-check still read win32-arm64 as missing
  though attempt 1 had published it, and npm rejected the publish with
  "cannot publish over the previously published versions".

Check the per-version document (`/<name>/<version>`) directly instead,
which the CDN does not cache, with retries for 5xx and network errors.
Treat npm's publish-conflict rejection as success. Let every platform
publish finish before failing, since exiting mid-upload orphans
`npm publish` processes whose upload can still land, and report all
failures together. Give the availability wait five minutes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PV2ZJ8dVTShiA3PSCGjCYm
@changeset-bot

changeset-bot Bot commented Sep 25, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: b4af4e5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@wyattjoh wyattjoh self-assigned this Sep 25, 2026
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: bc2af0ca-99c2-42ac-a534-1c3fe732bf94

📥 Commits

Reviewing files that changed from the base of the PR and between 2e15c8a and b4af4e5.

📒 Files selected for processing (6)
  • docs/releasing.md
  • scripts/lib/npm.test.ts
  • scripts/lib/npm.ts
  • scripts/lib/publish-order.test.ts
  • scripts/lib/publish-order.ts
  • scripts/releaser.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/javascript (auto-detected)
Files not reviewed due to moderation or processing errors (6)
  • scripts/lib/npm.ts
  • scripts/lib/npm.test.ts
  • scripts/lib/publish-order.ts
  • scripts/lib/publish-order.test.ts
  • scripts/releaser.ts
  • docs/releasing.md

Included review availability: 7 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 10 reviews per hour.


📝 Walkthrough

Walkthrough

The release tooling now checks per-version npm registry documents and retries eligible check failures. Publishing reports whether a package was newly published or already existed. Dependency publishing waits for all dependency operations to settle before reporting failures. The releaser logs duplicate-version results and waits up to five minutes for platform packages to become readable. The release documentation describes these behaviors.

Priority: ⬆️ High

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to b4af4

No specific issue requiring a fix before merge is established by the supplied evidence; normal release checks still apply.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: preventing npm registry read lag from causing release publish failures.
Description check ✅ Passed The description is directly related to the changes. It explains the npm read-lag cause, the retry behavior, publish-conflict handling, dependency synchronization, and extended availability wait.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 5 files. (1 skipped: 1 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review coverage is incomplete: 6 files could not be fully reviewed. Findings from completed review steps are included; see review info for details.


Comment @coderabbitai help to get the list of available commands.

@wyattjoh
wyattjoh marked this pull request as ready for review September 25, 2026 15:09
@wyattjoh
wyattjoh enabled auto-merge (squash) September 25, 2026 15:14
@wyattjoh
wyattjoh merged commit 6772446 into main Sep 25, 2026
10 checks passed
@wyattjoh
wyattjoh deleted the claude/publish-resilience-de8wq7 branch September 25, 2026 17:30
wyattjoh added a commit that referenced this pull request Sep 28, 2026
#498 moved the availability check to the per-version registry document,
which the CDN does not cache, and gave the wait five minutes. The first
canary after it merged (6772446) still failed: all eight platform
packages published, and none read back within five minutes from the
runner, though they were readable a few minutes later. The lag is on
npm's side, not in a cache we can bypass.

npm had already accepted every platform publish, and the wrapper is
subject to the same read lag, so failing the job only strands the
wrapper. Keep the wait as a best effort (two minutes), and on timeout
log a warning and publish the wrapper anyway.


Claude-Session: https://claude.ai/code/session_01PV2ZJ8dVTShiA3PSCGjCYm

Co-authored-by: Claude <noreply@anthropic.com>
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.

3 participants