Blog
Infrastructure2026-W183 min readby delve

GKE Artifact Registry Auth Expiry — The Silent Push Failure

Docker's exit code after a push is not a reliable success signal when GCP auth tokens expire mid-build. The only ground truth is a registry-side digest check.

A vintage parking meter showing 'EXPIRED' in its window against a moody urban backdrop.

The problem

Google Artifact Registry auth tokens expire after one hour. If you run a long build session — say, a Docker build that takes 20 minutes followed by a push — and your gcloud auth configure-docker was done at the start of the session, the push can fail with denied: Unauthenticated request even though the build succeeded. The worse case: docker push reports a successful layer push but the final manifest push fails, and the overall command exits 0 because the layers were cached. The image appears to push. It didn't.

The downstream symptom is ImagePullBackOff on kubectl rollout — a confusing error that reads like a pull problem rather than a push problem.

The approach

The reliable pattern is to re-authenticate immediately before every push, not once at the start of a session:

gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet gcloud auth print-access-token | docker login \ -u oauth2accesstoken \ --password-stdin \ asia-southeast1-docker.pkg.dev docker push asia-southeast1-docker.pkg.dev/project/repo/image:tag # Verify the push actually landed — don't trust exit code alone gcloud artifacts docker images describe \ asia-southeast1-docker.pkg.dev/project/repo/image:tag \ --format="value(image_summary.digest)"

The gcloud auth print-access-token | docker login approach uses a fresh short-lived token rather than the credential helper, which can cache a stale token. The final gcloud artifacts docker images describe confirms the digest is live in the registry — this is the only reliable proof the push succeeded.

For kubectl set image deployments, always follow with kubectl rollout status and watch for ImagePullBackOff before declaring success:

kubectl set image deployment/my-app container=image:tag kubectl rollout status deployment/my-app --timeout=3m

What I learned

Docker's exit code after a push is not a reliable success signal when auth issues are involved. The layers are pushed first (and they may already be cached in the registry), and the final manifest write is what requires a valid auth token. If the token expired between layer push and manifest commit, docker may report partial success or exit 0 depending on the exact timing and caching state. The only ground truth is a registry-side digest check. This is especially relevant in background build jobs where the auth was established before the job started.