A release job on Yarn 4.18.1 with npmPublishProvenance: true fails mid-changeset publish with YN0001: gM: error creating tlog entry - (409) an equivalent entry already exists in the transparency log with UUID 108e9186e8c5677a5434..., and the package never reaches the registry. The string appears nowhere in Yarn's docs, the upstream report (yarnpkg/berry#7308, opened 16 October 2026) is still open with no maintainer reply, and the cause sits in a hardcoded field of sigstore-js's client config. These twelve tips cover what to check before you bump a version, why retrying works, and which parts of the provenance path Yarn controls and which it does not.

yarn npm publish --provenancesigstore.attest builds the DSSE payloadPOST /api/v1/log/entries to rekor.sigstore.dev.sigstore bundle attached to the registry PUTfetchOnConflict false: throw YN0001release aborts before the registry PUT"201 Created""timeout: sigstore retries the POST""409 equivalent entry already exists"

The tips

  1. Read the 409 as a lost response, not a duplicate release. Rekor's createLogEntry maps a gRPC ALREADY_EXISTS onto http.StatusConflict and returns the existing entry's ID (pkg/api/entries.go). sigstore's client sets retry: options.retry ?? DEFAULT_RETRY on the Rekor witness, so a POST whose response is lost after the server committed gets sent a second time. The server rejects the duplicate, correctly, and that rejection ends your release.
  2. Prove what reached the registry before you touch the version number. Yarn builds the provenance bundle while assembling the publish body, so the .sigstore attachment and the tarball go up in a single PUT that never happened. Check both sides rather than assuming:
   curl -fsSL https://registry.npmjs.org/prettier-plugin-toml/4.0.0 | jq .dist.integrity
   curl -fsS https://registry.npmjs.org/-/npm/v1/attestations/prettier-plugin-toml@4.0.0 \
     | jq '.attestations[].predicateType'

A 404 from both means the version is still free and a re-run is safe. The attestations path is documented only in third-party tooling, so if you want a first-party answer, run npm audit signatures in a fresh install tree instead. Verifying the published tarball is a separate problem with its own failure modes, covered in the four packlist fixes behind pnpm publish missing files.

  1. Re-run the job before you debug it. In #7308 the fourth attempt published the same version in about ten seconds with no code change, and the release carries a slsa.dev/provenance/v1 attestation dated 2026-10-17T12:02:40Z. No local fix happened between attempts. Budget one automatic retry into the release stage rather than paging whoever owns the pipeline.
  2. Put --tolerate-republish on every publish line you might re-run. Yarn documents the flag as "Warn and exit when republishing an already existing version of a package" (yarn npm publish), which makes a half-finished multi-package release resumable instead of poisoned. Yarn's own 03-release-npm.sh runs yarn npm publish --tolerate-republish --provenance --access=public --staged. Signing is not the only step that can abort a publish partway through a monorepo: npm's file allowlist rejects tarballs for its own reasons, as in EALLOWFILE on publish, where allow-file=root fails too.
  3. Pull the UUID out of the error text and read the entry. The 409 message carries the sharded entry ID, which is enough to confirm your payload is already in the log:
   curl -fsS "https://rekor.sigstore.dev/api/v1/log/entries/108e9186e8c5677a5434..." \
     | jq -r '.[].body' | base64 -d | jq '.spec.content.payloadHash.value'

Compare that digest with the subject digest your build signed. If they match, the signature landed and the only casualty was the HTTP response.

  1. The field that would fix this lives in the library, and no Yarn setting reaches it. TLogClient in packages/sign/src/witness/tlog/client.ts defaults fetchOnConflict to true, and on a 409 it takes the UUID from the response and fetches the existing entry rather than throwing. The top-level client overrides that default when it wires up the witnesses:
   // sigstore-js packages/client/src/config.ts, initWitnesses()
   new RekorWitness({
     rekorBaseURL: options.rekorURL,
     entryType: options.legacyCompatibility ? 'intoto' : 'dsse',
     fetchOnConflict: false,
     retry: options.retry ?? DEFAULT_RETRY,
   })

Both sign() and attest() route through initWitnesses, and Yarn calls sigstore.attest() from packages/plugin-npm/sources/npmProvenance.ts. One part I could not confirm: whether Rekor's 409 response carries the Location header that entryExistsError() requires, since handleRekorAPIError receives the entry URL under an "entryURL" key. Reading pkg/api/error.go, or curl -i-ing a deliberately duplicated POST, settles it.

  1. Grep the Yarn release bundle, not the lockfile. yarn why sigstore reports nothing, because Yarn ships as one minified .cjs with its dependencies inlined. The file is a single line, so grep -c always answers 1; count matches instead:
   grep -o 'fetchOnConflict:![01]' .yarn/releases/yarn-4.18.1.cjs | sort | uniq -c

Yarn 4.18.0 upgraded that bundled copy to sigstore v4 (#7208, 29 July 2026), which makes the sigstore version you run a property of your yarnPath. Probing the artifact beats trusting a version table, the same discipline that applies when a Node build's version string lies about its Brotli decoder.

  1. Do not install a newer npm CLI to fix a yarn npm publish auth failure. Yarn runs its own OIDC exchange in getOidcToken inside packages/plugin-npm/sources/npmHttpUtils.ts. The floor npm publishes, "npm CLI version 11.5.1 or later and Node version 22.14.0 or higher" (npm trusted publishers), governs npm publish and is never read on the Yarn path. The identity side has its own trap, documented in npm OIDC "package not found" when your sub claim changes.
  2. On GitHub Actions, a missing permission produces its own error, not a 409. Yarn checks only that the token request URL is present and then fails with Provenance generation in GitHub Actions requires "write" access to the "id-token" permission. Grant it at job scope:
   permissions:
     contents: read
     id-token: write
  1. On GitLab, the audience is the setting people get wrong. Yarn expects SIGSTORE_ID_TOKEN with the sigstore audience and names both verbatim when the token is absent:
    publish:
      id_tokens:
        SIGSTORE_ID_TOKEN:
          aud: sigstore
  1. CircleCI can authenticate but cannot attest. OIDC auth for CircleCI landed in Yarn 4.14.0 (#7075) with a follow-up in 4.15.0 (#7122), closing yarnpkg/berry#7074. Provenance did not come with it: Yarn throws Provenance generation is only supported in GitHub Actions and GitLab CI, and npm's trusted-publishers page states provenance generation is not currently supported for CircleCI. Set provenance per package through publishConfig.provenance instead of enabling npmPublishProvenance across a monorepo that releases from mixed CI.
  2. On self-hosted runners, plan a token path now. npm's trusted-publisher docs say self-hosted runners "are not currently supported but are planned for future releases", so the OIDC exchange has nowhere to go. Yarn 4.18.0 also stopped prompting for OTP in non-TTY mode (#7209), turning a job that used to hang into a fast failure. Pass --otp, or stage the release with yarn npm publish --staged and approve it afterwards with yarn npm stage approve, which defers proof of presence out of the automated step.

Wrap-up

When a signing step fails, query the transparency log and the registry before you change anything locally. The 409 is Rekor reporting that it already holds your entry, and the failure is in how sigstore's client handles that answer. The opposite case deserves the same scepticism: npmPublishProvenance defaults to false, so a release you believe is attested may have written no entry at all. Make the attestations endpoint part of the release check rather than trusting the flag that was supposed to produce the bundle.

_What I read for this: yarnpkg/berry#7308, sigstore-js packages/client/src/config.ts and packages/sign/src/witness/tlog/client.ts, Rekor pkg/api/entries.go, the yarn npm publish CLI reference, and npm's trusted publishers documentation._