Docker "invalid reference format" in CI
Docker rejected an image reference. invalid reference format means the name/tag is malformed - uppercase in the repository part, illegal characters, an empty interpolated variable, or a stray colon/slash.
What this error means
A docker build -t, docker tag, docker push, or docker pull fails immediately with invalid reference format. The reference string is bad before any registry is contacted.
docker: invalid reference format
# e.g. docker build -t MyOrg/API:1.4.2 . (uppercase not allowed in repo name)
# or an empty var: docker build -t ghcr.io/myorg/api: .Diagnose it: separate auth from naming from rate limits
Registry errors look alike and have unrelated causes. Work out which of the three you have before changing credentials, because a malformed image reference produces an error that reads like an authentication failure.
# 1. is the reference even valid? (lowercase, no spaces, valid tag)
docker image inspect "$IMAGE" 2>&1 | head -2
# 2. are you authenticated to the right registry?
cat ~/.docker/config.json | grep -o '"[^"]*\.[^"]*"' | head
# 3. are you rate limited? (Docker Hub anonymous pulls)
curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimit-preview/test:pull" \
| grep -o '"token"' >/dev/null && echo "token ok"Common causes
Uppercase or illegal characters in the name
Repository names must be lowercase and use a limited character set. Uppercase letters or illegal characters make the reference invalid.
An empty interpolated variable
A tag built from ${VERSION} where the variable is unset collapses to image: or a missing component, which is malformed.
Stray or doubled separators
An extra colon, a trailing slash, or a double tag produces a reference Docker cannot parse.
How to fix it
Use a lowercase, fully-formed reference
Lowercase the repository and ensure every component is present.
docker build -t ghcr.io/myorg/api:1.4.2 .
# lowercase a dynamic name:
docker build -t "ghcr.io/$(echo "$ORG" | tr '[:upper:]' '[:lower:]')/api:1.4.2" .Default tag variables so they are never empty
Give the tag a fallback so an unset variable does not break the reference.
TAG="${VERSION:-latest}"
docker build -t ghcr.io/myorg/api:"$TAG" .Authenticate in the job, not in the image
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# GHCR needs this on the job or the push is rejected as unauthorised
permissions:
contents: read
packages: writeHow to prevent it
- Keep repository names lowercase and within the allowed character set.
- Default tag variables so an empty value cannot produce
image:. - Lint computed image references before using them.