Pypi package upload to local registry fails with "403 Forbidden - Insufficient permissions to access this resource in project packages. The following token permission is required: admin_packages.""

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Hi,

I'm having an issue with upload of CI-built package to the package registry, using pypi / uv.

I'm using \$CI_JOB_TOKEN as authentication password, with username gitlab-ci-token as username.

What happens

I'm trying to upload a CI-built package to a local package registry. When using the following command, it works :

$ uv publish --index gitlab.ville.tg --verbose --dry-run dist/*

(the --dry-run only simulate the package upload)

Then I try to perform the real upload :

$ uv publish --index gitlab.ville.tg --verbose dist/*
DEBUG uv 0.9.10
DEBUG Publishing with index gitlab.ville.tg
Publishing 2 files to https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi
DEBUG Using request timeout of 900s
DEBUG Checking for elise_client-0.6.2-py3-none-any.whl in the registry
DEBUG No cache entry for: https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi/simple/elise-client/
Uploading elise_client-0.6.2-py3-none-any.whl (10.8KiB)
DEBUG Hashing dist/elise_client-0.6.2-py3-none-any.whl
DEBUG Skipping validation request for unsupported publish URL: https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi
DEBUG Using HTTP Basic authentication
DEBUG Response code for https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi: 403 Forbidden
DEBUG Upload error response: {"message":"403 Forbidden - Insufficient permissions to access this resource in project packages. The following token permission is required: admin_packages."}
DEBUG Checking for elise_client-0.6.2-py3-none-any.whl in the registry
DEBUG Found stale response for: https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi/simple/elise-client/
DEBUG Sending revalidation request for: https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi/simple/elise-client/
DEBUG Found modified response for: https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi/simple/elise-client/
error: Failed to publish `dist/elise_client-0.6.2-py3-none-any.whl` to https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi
  Caused by: Upload failed with status code 403 Forbidden. Server says: {"message":"403 Forbidden - Insufficient permissions to access this resource in project packages. The following token permission is required: admin_packages."}

## Versions

GitLab

sudo gitlab-rake gitlab:env:info
System information
System:		Debian 13
Current User:	git
Using RVM:	no
Ruby Version:	3.2.8
Gem Version:	3.7.1
Bundler Version:2.7.1
Rake Version:	13.0.6
Redis Version:	7.2.11
Sidekiq Version:7.3.9
Go Version:	unknown

GitLab information
Version:	18.5.2
Revision:	45f7473ea37
Directory:	/opt/gitlab/embedded/service/gitlab-rails
DB Adapter:	PostgreSQL
DB Version:	16.10
URL:		https://gitlab.ville.tg
HTTP Clone URL:	https://gitlab.ville.tg/some-group/some-project.git
SSH Clone URL:	git@gitlab.ville.tg:some-group/some-project.git
Using LDAP:	yes
Using Omniauth:	yes
Omniauth Providers: 

GitLab Shell
Version:	14.45.3
Repository storages:
- default: 	unix:/var/opt/gitlab/gitaly/gitaly.socket
GitLab Shell path:		/opt/gitlab/embedded/service/gitlab-shell

Gitaly
- default Address: 	unix:/var/opt/gitlab/gitaly/gitaly.socket
- default Version: 	18.5.2
- default Git Version: 	2.50.1

GitLab-Runner

$ gitlab-runner --version

Version:      18.5.0
Git revision: bda84871
Git branch:   18-5-stable
GO version:   go1.24.6 X:cacheprog
Built:        2025-10-13T19:20:30Z
OS/Arch:      linux/amd64

Job

upload-package-gitlab:
  stage: upload
  needs:
    - check-package
  rules:
    - if: $CI_COMMIT_TAG != null
  variables:
    UV_PUBLISH_USERNAME: gitlab-ci-token
    UV_PUBLISH_PASSWORD: $CI_JOB_TOKEN
  before_script:
    - *install_cert
    - *install_uv
  script:
    - uv publish --index gitlab.ville.tg --verbose dist/*
  artifacts:
    paths:
      - dist/*
    expire_in: 1 week
  tags:
    - python3.11
    - docker

The upload index gitlab.ville.tg is defined in my pyproject.toml :

[[tool.uv.index]]
name = "gitlab.ville.tg"
url = "https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi/simple"
publish-url = "https://gitlab.ville.tg/api/v4/projects/fguerin%2Fpackages/packages/pypi"
explicit = true

Thanks for your help !

Edited by 🤖 GitLab Bot 🤖