I spent way too long trying to get uv publish to work with Google Artifact Registry. The docs suggest using keyring, but that led me down a rabbit hole of authentication errors.

The error Link to heading

My first attempt was the keyring approach from the uv docs:

uv tool install keyring --with keyrings.google-artifactregistry-auth
uv publish --index my-registry dist/*

This gave me a 401:

error: Failed to publish `my-package-0.1.0.tar.gz` to my-registry
  Caused by: Upload failed with status code 401 Unauthorized

Even with gcloud auth application-default login configured, it just wouldn’t pick up the credentials.

What actually works Link to heading

Skip keyring entirely. Pass the OAuth2 token directly:

uv publish --index my-registry \
    --username oauth2accesstoken \
    --password $(gcloud auth print-access-token) \
    dist/*

The magic is oauth2accesstoken as the username - that’s how GCP knows you’re authenticating via OAuth2 rather than basic auth.

Setting up pyproject.toml Link to heading

You’ll need to define your index in pyproject.toml:

[[tool.uv.index]]
name = "my-registry"
url = "https://europe-west2-python.pkg.dev/your-project/your-repo/"
publish-url = "https://europe-west2-python.pkg.dev/your-project/your-repo/"

The region prefix matters - use whatever region your Artifact Registry is in.

CI/CD with GitHub Actions Link to heading

For automation, use Workload Identity Federation so you’re not storing service account keys:

- name: Authenticate to GCP
  uses: google-github-actions/auth@v2
  with:
    workload_identity_provider: ${{ vars.WIF_PROVIDER }}
    service_account: ${{ vars.SERVICE_ACCOUNT }}

- name: Publish to Artifact Registry
  run: |
    uv build
    uv publish --index my-registry \
      --username oauth2accesstoken \
      --password $(gcloud auth print-access-token) \
      dist/*

Debugging Link to heading

If you’re still getting 401s, add -vv to see what’s happening:

uv publish --index my-registry --username oauth2accesstoken dist/* -vv

Common issues:

  • Wrong region in the URL
  • Service account missing roles/artifactregistry.writer
  • Forgot to run uv build first

Further reading Link to heading