PatchRail

Publish and release conflicts — EPUBLISHCONFLICT / File already exists

Log signatures

You cannot publish over the previously published versions
EPUBLISHCONFLICT
HTTPError: 400 File already exists
crate version 1.2.3 is already uploaded
a release with the same tag already exists

What’s happening

Two causes cover nearly everything: version-already-exists (EPUBLISHCONFLICT, PyPI's "File already exists", crates.io's "already uploaded", GitHub's "already_exists" on a tag) — most registries are immutable by design; you can never republish a version, even to fix it. This fires when a release job re-runs after a partial failure (half the artifacts published, half didn't) or when the version wasn't bumped. And auth failures (ENEEDAUTH, E403, 403 Forbidden) — the publish credential is missing, expired, or lacks rights to this package name; PyPI in particular returns 403 (not 404) for "name taken by someone else."

Fix playbook

  1. 1Determine which artifacts of the release actually made it (check the registry directly). Partial publishes are the norm in this failure class.
  2. 2Version conflict: bump the version — even for a one-character fix. Fighting registry immutability is a losing game, and it exists so that a given version is forever the same bytes for everyone.
  3. 3Re-run only the publish step, with already-published artifacts skipped (twine upload --skip-existing, conditional steps per artifact). Re-running the whole release pipeline re-builds and can produce different bytes.
  4. 4Auth: verify which token the step actually uses (env var name, trusted-publisher config) and its scopes/expiry. Don't print it while debugging.
  5. 5Tag conflicts: decide whether the existing tag is the release (then skip creation) or a stale tag (then delete deliberately, knowing consumers may have fetched it).

Prevention

  • Make releases idempotent — every publish step either skips-if-exists or is conditional on a registry check. A safely re-runnable release pipeline turns this whole class into a non-event.

Triage every red build, not just this one.

This page is one of 31 failure classes the open-source patchrail CLI matches from a raw log — locally, with secrets redacted first. If a log stumps it, open an issue; if it saves you a debugging morning, a star helps other maintainers find it.

★ Star on GitHubpipx install patchrail