1. Introduction

AWS Elastic Container Registry (ECR) doesn't use static credentials like Docker Hub. It uses short-lived tokens generated by the AWS CLI, which expire every 12 hours. This design is more secure — but it also means authentication failures happen more often and for more varied reasons.

This guide covers every common ECR login failure: expired tokens, missing IAM permissions, misconfigured credential helpers, cross-account access problems, and failures specific to CI/CD pipelines and Kubernetes. For each one you'll get the exact error message to look for, a diagnosis command, and the fix.

2. How ECR Authentication Works

Before debugging, it helps to understand the authentication flow. ECR does not accept a static username and password. Instead:

This means authentication failures have two broad categories: problems getting the token (IAM, credentials, region) and problems using the token (expired, wrong registry URL, missing credential helper).

# The standard ECR login command aws ecr get-login-password --region <region> \ | docker login --username AWS --password-stdin \     <account-id>.dkr.ecr.<region>.amazonaws.com
      # Example for us-east-1: aws ecr get-login-password --region us-east-1 \ | docker login --username AWS --password-stdin \     123456789012.dkr.ecr.us-east-1.amazonaws.com

3. Common Causes

4. Step-by-Step Diagnosis and Fix

Step 1: Read the exact error message

ECR authentication failures produce different errors depending on where the problem is. Before doing anything, capture the exact message:

# Run with verbose output to see the full error aws ecr get-login-password --region us-east-1 2>&1
      # Then try the full login command and capture output aws ecr get-login-password --region us-east-1 \ | docker login --username AWS --password-stdin \     123456789012.dkr.ecr.us-east-1.amazonaws.com 2>&1

Common error signatures and what they indicate:

Error message / signalLikely cause
An error occurred (UnauthorizedException)IAM lacks ecr:GetAuthorizationToken — fix: add the permission to the IAM policy
Error: Cannot perform an interactive loginPiping issue or docker credential helper conflict — fix: check credential helper config
unauthorized: authentication requiredToken expired or not passed correctly — fix: re-run get-login-password and docker login
no basic auth credentialsdocker login was never run for this registry — fix: run the full ECR login command
denied: User is not authorized to perform: ecr:*Missing ECR repository-level IAM permission — fix: add policy for the specific actions
no such host / could not resolveWrong region or account ID in registry URL — fix: verify the registry URI format
RequestExpired / Token has expiredSystem clock skew or using an old token — fix: sync clock, re-generate token

Step 2: Verify AWS credentials are present and correct

The most fundamental check — confirm that valid AWS credentials exist in the environment where the login command runs:

# Check which credentials are active aws sts get-caller-identity
      # Expected output (IAM user):
      # {
      #     "UserId": "AIDAEXAMPLEID",
      #     "Account": "123456789012",
      #     "Arn": "arn:aws:iam::123456789012:user/ci-deploy"
      # }
      # Expected output (IAM role / instance profile):
      # {
      #     "UserId": "AROAEXAMPLEID:session-name",
      #     "Account": "123456789012",
      #     "Arn": "arn:aws:sts::123456789012:assumed-role/my-role/session-name"
      # }
      # If this fails, your credentials are missing or invalid.
      # Check environment variables: echo $AWS_ACCESS_KEY_ID echo $AWS_PROFILE cat ~/.aws/credentials

Step 3: Check the IAM permissions

Getting an ECR token and pulling or pushing images requires specific IAM actions. Check what the active identity is allowed to do:

# Simulate the ecr:GetAuthorizationToken permission aws iam simulate-principal-policy \   --policy-source-arn arn:aws:iam::123456789012:user/ci-deploy \   --action-names ecr:GetAuthorizationToken \   --resource-arns '*'
      # Check effective permissions for ECR actions on a specific repo aws iam simulate-principal-policy \   --policy-source-arn arn:aws:iam::123456789012:user/ci-deploy \   --action-names ecr:BatchGetImage ecr:GetDownloadUrlForLayer \     ecr:InitiateLayerUpload ecr:UploadLayerPart \     ecr:CompleteLayerUpload ecr:PutImage \   --resource-arns arn:aws:ecr:us-east-1:123456789012:repository/myapp

Minimum IAM policy for ECR pull:

{   "Version": "2012-10-17",   "Statement": [     {       "Effect": "Allow",       "Action": "ecr:GetAuthorizationToken",       "Resource": "*"     },     {       "Effect": "Allow",       "Action": [         "ecr:BatchCheckLayerAvailability",         "ecr:GetDownloadUrlForLayer",         "ecr:BatchGetImage"       ],       "Resource": "arn:aws:ecr:<region>:<account-id>:repository/<repo-name>"     }   ] }

For push access, add these actions to the resource-scoped statement:

Step 4: Fix an expired token

If you authenticated successfully before but now get 'no basic auth credentials' or '401 Unauthorized', your 12-hour token has expired. The fix is simply to re-run the login command:

# Re-authenticate to ECR aws ecr get-login-password --region <region> \ | docker login --username AWS --password-stdin \     <account-id>.dkr.ecr.<region>.amazonaws.com
      # Confirm the new credential is stored cat ~/.docker/config.json | grep dkr.ecr

In CI/CD pipelines, this should happen at the start of every pipeline run, not once during setup. A token from a previous pipeline run will be stale by the time the next run executes — especially for scheduled or infrequent pipelines.

Step 5: Verify the registry URL format

A wrong account ID or region in the registry URL produces misleading errors. Double-check the exact format:

# Correct private ECR registry URL format:
      # <12-digit-account-id>.dkr.ecr.<region>.amazonaws.com
      # Verify your account ID aws sts get-caller-identity --query Account --output text
      # List your ECR repositories with their full URIs aws ecr describe-repositories --region <region> \   --query 'repositories[*].repositoryUri' --output table
      # Common mistakes:
      # Wrong:   123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp  (missing region match)
      # Wrong:   dkr.ecr.us-east-1.amazonaws.com/myapp               (missing account ID)
      # Correct: 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp

Step 6: Fix cross-account ECR access

If you're pulling an image from an ECR repository in a different AWS account, the repository needs a resource-based policy that explicitly grants access to the calling account or role:

# Check the current ECR repository policy aws ecr get-repository-policy \   --repository-name myapp \   --region us-east-1
      # Add a policy that grants cross-account pull access aws ecr set-repository-policy \   --repository-name myapp \   --region us-east-1 \   --policy-text '{     "Version": "2012-10-17",     "Statement": [       {         "Sid": "CrossAccountPull",         "Effect": "Allow",         "Principal": {           "AWS": "arn:aws:iam::<calling-account-id>:root"         },         "Action": [           "ecr:BatchGetImage",           "ecr:GetDownloadUrlForLayer",           "ecr:BatchCheckLayerAvailability"         ]       }     ]   }'

For cross-account access, the calling identity still needs ecr:GetAuthorizationToken in their own account — you cannot delegate that via a resource policy. The resource policy only governs the repository-level actions (pull/push).

Step 7: Fix the ECR credential helper

The Amazon ECR Credential Helper (docker-credential-ecr-login) automates token refresh so you never have to run docker login manually. If it's misconfigured, you may see 'no basic auth credentials' even when your IAM permissions are correct:

# Install the credential helper (Linux) sudo apt-get install amazon-ecr-credential-helper
      # Or: go install github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login@latest
      # Configure Docker to use it for all ECR registries
      # Add to ~/.docker/config.json: {   "credHelpers": {     "<account-id>.dkr.ecr.<region>.amazonaws.com": "ecr-login"   } }
      # Or configure it as the default helper for all ECR domains: {   "credsStore": "ecr-login" }
      # Test the helper directly docker-credential-ecr-login get \   <<< '<account-id>.dkr.ecr.<region>.amazonaws.com'

5. Verification Steps

Once you've applied your fix, run these checks to confirm authentication is working end-to-end:

# 1. Confirm AWS identity aws sts get-caller-identity
      # 2. Get a fresh ECR token aws ecr get-login-password --region <region>
      # Should output a long base64 token string, no errors
      # 3. Run the full login aws ecr get-login-password --region <region> \ | docker login --username AWS --password-stdin \     <account-id>.dkr.ecr.<region>.amazonaws.com
      # Expected: Login Succeeded
      # 4. Pull a known image from ECR to confirm end-to-end docker pull <account-id>.dkr.ecr.<region>.amazonaws.com/<repo>:<tag>
      # 5. For push access, verify by pushing a test tag docker tag alpine:latest \   <account-id>.dkr.ecr.<region>.amazonaws.com/<repo>:test docker push <account-id>.dkr.ecr.<region>.amazonaws.com/<repo>:test

6. Common Mistakes

7. Prevention Tips

8. Summary

ECR authentication failures are almost always one of four things: missing IAM permissions, an expired token, a wrong registry URL, or a misconfigured credential helper. Here's the quick-reference diagnostic:

SymptomMost likely cause and fix
UnauthorizedException on get-login-passwordIAM lacks ecr:GetAuthorizationToken — add it with Resource: "*"
no basic auth credentialsToken expired or login never run — re-run the full ECR login command
denied: not authorized to perform ecr:*Missing repo-level IAM permissions — add BatchGetImage and related actions
no such host / DNS failureWrong region or account ID in registry URL — verify with ecr describe-repositories
cross-account 403Missing ECR repository resource policy — add cross-account principal
works locally, fails in CICI environment missing AWS credentials — check env vars and IAM role binding
works today, fails tomorrow12-hour token expiry — add login step to pipeline; use credential helper or IRSA

For any environment running long-lived workloads — Kubernetes clusters, persistent CI agents, or always-on build servers — the right long-term fix is to eliminate static ECR tokens entirely by using the credential helper or IRSA. When ECR auth fails in a running Kubernetes cluster, it surfaces as ImagePullBackOff. The 12-hour expiry will catch you eventually if you don't.