twine / PyPI trusted publishing OIDC failure in CI
Trusted publishing lets CI upload to PyPI with a short-lived OIDC token instead of a long-lived API token. It fails when the workflow lacks id-token: write, or when the OIDC claims (repo, workflow, environment) do not match the trusted publisher configured on PyPI.
What this error means
The pypa/gh-action-pypi-publish step fails with "OpenID Connect token ... could not be exchanged", or PyPI returns "invalid-publisher: valid token, but no corresponding publisher" because the configured publisher does not match the workflow.
Error: invalid-publisher: valid token, but no corresponding publisher (Publisher with matching claims was not found)
This generally indicates a trusted publisher configuration error on PyPI.Common causes
The job lacks id-token: write permission
Without permissions: id-token: write, GitHub will not mint the OIDC token, so the action cannot exchange it for a PyPI upload token.
The trusted publisher claims do not match
PyPI verifies the repository, workflow filename, and (optional) environment in the OIDC claims. If any differs from what was registered, PyPI returns invalid-publisher.
How to fix it
Grant id-token: write and use the publish action
Add the OIDC permission and upload with the official action; no API token is needed under trusted publishing.
permissions:
id-token: write
jobs:
publish:
steps:
- uses: pypa/gh-action-pypi-publish@release/v1Match the trusted publisher on PyPI
- In the PyPI project settings, register the publisher with the exact owner/repo.
- Set the workflow filename to match the file that runs the publish.
- If you set an environment on PyPI, add
environment:to the job so the claim matches.
How to prevent it
- Configure the trusted publisher with the exact repo, workflow file, and environment.
- Keep
id-token: writeon the publishing job. - Prefer trusted publishing over long-lived API tokens for PyPI releases.