GitLab CI Protected Variable Empty on Unprotected Branch
A CI/CD variable read as empty because it is marked "protected". Protected variables are only injected on pipelines for protected branches and tags - not on feature branches or merge-request pipelines.
What this error means
A deploy or auth step fails because a secret is blank on a feature branch but works on main. The variable is defined, yet the job sees an empty value depending on the ref.
$ echo "deploying with token length: ${#DEPLOY_TOKEN}"
deploying with token length: 0
$ ./deploy.sh
Error: missing DEPLOY_TOKENCommon causes
Variable is protected, branch is not
A "Protected" CI/CD variable is exposed only to pipelines running on protected branches/tags. On an unprotected feature branch it is simply not present.
Masking constraints silently drop it
A "Masked" variable whose value does not meet GitLab’s masking requirements may be disabled, leaving the job without it.
How to fix it
Run the job on a protected ref or unprotect the variable
- If the secret is only for deploys, gate the job to protected branches/tags with
rules. - If it must run on feature branches, uncheck "Protected" on the variable (accepting the broader exposure).
- Protect the branch/tag pattern that legitimately needs the secret.
Verify presence before using it
Fail fast with a clear message instead of a confusing downstream error.
deploy:
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
script:
- test -n "$DEPLOY_TOKEN" || { echo "DEPLOY_TOKEN missing (protected?)"; exit 1; }
- ./deploy.shHow to prevent it
- Keep deploy secrets protected and gate deploy jobs to protected refs.
- Document which variables are protected so contributors expect the behavior.
- Ensure masked values satisfy GitLab’s masking rules so they are not disabled.