Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for GitLab CI/CD By James Joyner IV · · 9 min read

GitLab CI Error Guide: 'You are not allowed to download code from this project' Job Token 403

Fix GitLab CI's 'not allowed to download code' / 403 when CI_JOB_TOKEN clones another project: add the consuming project to the Token Access allowlist or use a deploy token.

  • #gitlab-cicd
  • #troubleshooting
  • #errors
  • #authentication

Exact Error Message

You have authenticated correctly with CI_JOB_TOKEN, but cloning another project still fails — this time with a 403, not a missing-credentials error:

remote: You are not allowed to download code from this project.
fatal: unable to access 'https://gitlab.com/acme/shared-lib.git/': The requested URL returned error: 403

The credential reached GitLab and was recognised; it was then rejected. This is an authorization failure, not an authentication failure.

What the Error Means

Since GitLab 16.0, the CI/CD job token is default-deny across projects. A job token issued for project A can only pull from project B if project B has explicitly added project A to its job token allowlist (Settings > CI/CD > Token Access > “Allow access to this project with a CI_JOB_TOKEN”). Without that entry, GitLab knows who is asking — the gitlab-ci-token user backed by CI_JOB_TOKEN — and answers: that user is not allowed to download code here.

So unlike the “could not read Username” failure (no credentials at all), here the credential is valid; the source project simply hasn’t granted access to the consuming project.

Common Causes

  1. Job token allowlist doesn’t include the consuming project. The most common cause on GitLab 16+: the source project’s “Limit access to this project” is on, and your pipeline’s project isn’t on the list.
  2. Project visibility. A private source project never serves code to a job token unless explicitly allowlisted, regardless of group membership.
  3. Default-deny job-token scope (GitLab 16+). New projects ship with the inbound allowlist enabled and empty, so every cross-project token clone is denied until configured.
  4. Member permissions. The pipeline’s project (acting as the gitlab-ci-token user) needs at least Reporter-equivalent access to download code from the source.
  5. Wrong token entirely. Using a deploy token/PAT that lacks read_repository scope produces the same 403.

How to Reproduce the Error

On GitLab 16+ with default settings, clone a sibling private project with the job token:

consume:
  stage: build
  image: alpine/git
  script:
    - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/acme/shared-lib.git

The token authenticates, but shared-lib has not allowlisted this pipeline’s project:

$ git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/acme/shared-lib.git
Cloning into 'shared-lib'...
remote: You are not allowed to download code from this project.
fatal: unable to access 'https://gitlab.com/acme/shared-lib.git/': The requested URL returned error: 403

Diagnostic Commands

The fix is mostly in the UI, but confirm the request and the token’s identity from the job:

# Confirm the token is being sent (HTTP, not a missing-credential failure)
GIT_CURL_VERBOSE=1 git ls-remote \
  https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/acme/shared-lib.git 2>&1 | grep -i '< HTTP'
< HTTP/2 403

A 403 (not a credential prompt) confirms this is an allowlist problem. Then check the settings:

  • Source project > Settings > CI/CD > Token Access > “Allow access to this project with a CI_JOB_TOKEN” — is the consuming project listed?
  • Source project > Project members — does the consuming project have at least Reporter access?
  • Note the predefined variables that identify the caller: CI_PROJECT_PATH (who is asking) and CI_PROJECT_ID.

Step-by-Step Resolution

1. Add the consuming project to the source project’s allowlist

In the source project (shared-lib): Settings > CI/CD > Token Access > expand “Allow access to this project with a CI_JOB_TOKEN” > Add project > enter the consuming project (acme/app).

This is the inbound allowlist: “which other projects’ job tokens may pull from me.” Once acme/app is listed, its pipelines can clone shared-lib.

2. Verify the consuming project has Reporter access

The job acts as the gitlab-ci-token user. Add the consuming project (or a group) as a member of the source with at least Reporter in Project members, so it is permitted to download code.

3. Re-run and confirm

consume:
  stage: build
  image: alpine/git
  script:
    - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/acme/shared-lib.git
    - echo "cloned $(ls shared-lib | wc -l) entries"
Cloning into 'shared-lib'...
remote: Enumerating objects: 142, done.
cloned 17 entries

4. Alternative — use a deploy token or PAT

If you cannot manage allowlists (e.g. the source is in another organisation), create a deploy token with read_repository (Settings > Repository > Deploy tokens) and pass it as masked variables:

before_script:
  - git config --global url."https://${DEPLOY_USER}:${DEPLOY_TOKEN}@gitlab.com/".insteadOf "https://gitlab.com/"

5. Manage at the group level

For many consumers, allowlist a whole group rather than individual projects, and use group-level CI/CD variables so credentials are defined once.

Prevention and Best Practices

  • Treat the job-token allowlist as part of your project setup: when a project becomes a shared dependency, add its consumers under Token Access immediately.
  • Keep “Limit access to this project with a CI_JOB_TOKEN” enabled (the secure default) and grant narrowly — never disable it to “make CI work.”
  • Grant the consuming project Reporter (not Developer) on the source unless write access is genuinely needed.
  • Prefer allowlisting a group over a long list of individual projects, and document the dependency so it survives team changes.
  • The free incident assistant can map a 403 log to the exact Token Access setting to change. More patterns live in the GitLab CI/CD guides.

Frequently Asked Questions

Why did this start happening after a GitLab upgrade?

GitLab 16.0 made the inbound job-token allowlist default-deny. Pipelines that previously cloned sibling projects freely now get a 403 until the source project allowlists the consumer under Settings > CI/CD > Token Access.

What’s the difference between this 403 and “could not read Username”?

“Could not read Username” means no credentials were sent at all (authentication). This 403 means the job token was sent and recognised, but the source project hasn’t authorized it (authorization). Fix the first by embedding CI_JOB_TOKEN; fix this one in Token Access settings.

Do I edit the allowlist on the source project or the consuming project?

On the source project — the one being cloned. Its inbound allowlist controls which other projects’ job tokens may download its code.

Can I just turn the allowlist off?

You can, but don’t. Disabling “Limit access to this project” lets any job token in the instance read the project. Add the specific consumers (or their group) instead.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.