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 buildfirst
Further reading Link to heading
- uv publish documentation
- Artifact Registry Python setup
- Running scripts with uv - general uv usage
- How uv got so fast - deep dive into uv’s performance
- uv is the best thing to happen to Python - Emily Hunt’s take