Skip to content

fix(ci): stop double npm publish on bot releases (TLOG 409)#187

Merged
punitarani merged 1 commit into
mainfrom
claude/fix-npm-double-publish
May 24, 2026
Merged

fix(ci): stop double npm publish on bot releases (TLOG 409)#187
punitarani merged 1 commit into
mainfrom
claude/fix-npm-double-publish

Conversation

@punitarani

@punitarani punitarani commented May 24, 2026

Copy link
Copy Markdown
Owner

Summary

Running release-npm published the same version twice, and the second publish failed with:

npm error code TLOG_CREATE_ENTRY_ERROR
npm error error creating tlog entry - (409) an equivalent entry already exists in the transparency log

Root cause — a double-publish race. release-npm.yml runs as github-actions[bot] and does two things that each lead to a publish of the same artifact:

  1. It calls publish-npm.yml via workflow_call (the canonical publish path).
  2. It creates the fli-js-v* tag + GitHub Release — and publish-npm.yml also triggers on release: published, so the bot-created Release fired a second npm-publish.

Two npm publish --provenance runs for the identical artifact submit the identical provenance bundle to the Sigstore transparency log; the second collides → 409 / TLOG_CREATE_ENTRY_ERROR. (@punitarani/fli@0.0.4 ended up not published as a result — the registry write never completed; current latest is 0.0.3.)

The PyPI side already guards against this exact race in publish.yml (github.actor != 'github-actions[bot]'); the npm side was missing the equivalent guard.

Change

.github/workflows/publish-npm.yml — exclude bot-created releases from the release-triggered publish:

 if: |
-  (github.event_name == 'release' && startsWith(github.event.release.tag_name, 'fli-js-v'))
+  (github.event_name == 'release' && github.actor != 'github-actions[bot]' && startsWith(github.event.release.tag_name, 'fli-js-v'))
   || inputs.environment == 'npm'

Behavior after the fix:

  • release-npm (bot) workflow_callinputs.environment == 'npm' → publishes once. ✅
  • bot Release event (the duplicate) → excluded by the actor guard → skips. ✅ (no more 409)
  • human-created fli-js-v* Release (manual fallback) → still publishes. ✅
  • manual workflow_dispatch env=npm → still publishes. ✅

After merge

  • 0.0.4 is burned (its provenance tlog entry already exists, and it's unpublished). Don't try to reuse it. main is already at 0.0.4, so the next release-npm run bumps to 0.0.5 and will publish exactly once.
  • Re-running release-npm will now work end-to-end.

https://claude.ai/code/session_01R2vZihmSWV2wvRawjF4Gjo


Generated by Claude Code

Greptile Summary

This PR adds a github.actor != 'github-actions[bot]' guard to the npm-publish job's if condition in publish-npm.yml, mirroring the identical guard already present on the PyPI side. The fix eliminates a double-publish race where release-npm.yml both called publish-npm.yml directly via workflow_call and created a GitHub Release that re-triggered the same workflow, causing a Sigstore transparency log collision (TLOG 409).

  • The guard is correctly scoped: it only affects the release:-triggered path; the workflow_call path (inputs.environment == 'npm') is unaffected and remains the canonical publish route.
  • Human-created fli-js-v* releases (manual fallback) continue to work because a human actor passes the new check.
  • Note that when the bot creates its release, fli-js-tests and release-build still run a second time (they lack the bot-actor guard), wasting a small amount of CI minutes, but npm-publish is correctly skipped so no functional regression occurs.

Confidence Score: 5/5

Safe to merge — single-line condition change with well-understood scope and a direct parallel in the existing PyPI guard.

The change is a targeted, one-clause addition to a GitHub Actions if expression. Both branches of the condition (workflow_call via inputs.environment == 'npm' and human release events) are exercised as before; only the bot-created release path is newly excluded. The logic exactly mirrors the battle-tested PyPI guard already in the repo.

No files require special attention.

Important Files Changed

Filename Overview
.github/workflows/publish-npm.yml Adds github.actor != 'github-actions[bot]' guard to the npm-publish job's if condition, preventing a second publish triggered by the bot-created GitHub Release from racing against the canonical workflow_call publish path.

Sequence Diagram

sequenceDiagram
    actor Human
    participant RN as release-npm.yml
    participant PUB as publish-npm.yml
    participant GHR as GitHub Release
    participant NPM as npm registry

    Human->>RN: "workflow_dispatch (bump=patch)"
    RN->>RN: bump version, commit, push tag
    RN->>GHR: "gh release create fli-js-vX.Y.Z (actor=github-actions[bot])"
    RN->>PUB: "workflow_call (inputs.environment=npm)"

    Note over GHR,PUB: release:published event fires
    GHR-->>PUB: "release event (actor=github-actions[bot])"

    PUB->>PUB: npm-publish if check
    Note over PUB: workflow_call path: inputs.environment=='npm' → TRUE ✅
    PUB->>NPM: npm publish --provenance ✅

    PUB->>PUB: npm-publish if check (release event path)
    Note over PUB: release path: github.actor=='github-actions[bot]' → SKIP ✅
    Note over PUB: Before fix: second publish → TLOG 409 error ❌
Loading

Reviews (1): Last reviewed commit: "fix(ci): stop double npm publish on bot ..." | Re-trigger Greptile

release-npm.yml runs as github-actions[bot]: it creates the
fli-js-v* tag/Release AND publishes by calling publish-npm.yml via
workflow_call. But publish-npm.yml also triggers on `release: published`,
so the bot-created Release fired a SECOND publish of the identical
artifact. Two provenance submissions for the same version collide on the
Sigstore transparency log:

  npm error code TLOG_CREATE_ENTRY_ERROR
  npm error error creating tlog entry - (409) an equivalent entry already exists

Exclude github-actions[bot] from the release-triggered publish so only the
workflow_call path (release-npm) publishes. Human-created Releases and
explicit environment=npm dispatches still publish. This mirrors the
existing guard in publish.yml (PyPI), which excludes bot releases for the
same reason.
@github-actions

Copy link
Copy Markdown
Contributor

Test Results

    4 files      4 suites   1m 23s ⏱️
  400 tests   400 ✅ 0 💤 0 ❌
1 600 runs  1 600 ✅ 0 💤 0 ❌

Results for commit e2dedd3.

@punitarani punitarani merged commit 88d9d1d into main May 24, 2026
13 checks passed
@punitarani punitarani deleted the claude/fix-npm-double-publish branch May 24, 2026 02:03
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.

2 participants