Docker push to ECR repository does not exist
Docker push to ECR repository does not exist means the registry accepted your credentials and then found nothing to push into, so create the repository first: Amazon ECR only makes one during a push when a repository creation template matches the name. The login is not the problem, which is why the fix is in your infrastructure rather than in your workflow credentials.

What this error means
The login step passes, the layers start uploading or fail immediately, and the push ends on a "name unknown" error that names the repository and the registry id. The registry id is your AWS account number and the host carries the region, so the message is telling you exactly where it looked. It is deterministic: the same push fails the same way until a repository exists at that name, in that account, in that region. We have not reproduced this one on a runner, because a real push needs AWS credentials and an account we are not going to put in a public page, so the log below is the shape ECR prints rather than a recorded run. Everything else on this page is quoted from the AWS documentation, read on 2026-09-20.
The push refers to repository [123456789012.dkr.ecr.us-east-1.amazonaws.com/api]
name unknown: The repository with name 'api' does not exist in the registry with id '123456789012'ECR does not create the repository for you, with one exception
The AWS documentation is direct about it: "The Amazon ECR repository must exist before you push the image, or you must have a repository creation template defined." The template is the exception, and it is narrow. A template carries a repository name prefix and a list of actions it applies for, which can include CREATE_ON_PUSH, and only a push whose repository name matches that prefix gets a repository made for it.
Without a matching template, AWS says plainly that "Amazon ECR will not create a repository with default settings" for an image push. That is a deliberate difference from a pull-through cache, where ECR does fall back to default settings when no template matches.
| How the repository gets there | What it costs you |
|---|---|
A create-repository call in the pipeline | One idempotent step, plus an IAM action the push policy does not include |
| Terraform or another infrastructure tool | A plan and apply before the first deploy, and one place that owns settings |
A repository creation template with CREATE_ON_PUSH | A prefix to match, and a creation role when the template sets tags or KMS |
| Nothing | This error, on the first push of every new service |
Common causes
The repository was never created
The first deploy of a new service, or a service renamed in the workflow and nowhere else. Everything up to the push works, which is what makes it confusing: the credentials are valid, the image built, and the registry is real. Only the repository is missing.
The push is pointed at the wrong region or account
A copied workflow keeps a region, a role change moves the account, or a matrix deploys to two regions from one reference. The repository exists, just not where the push looked. The registry id in the error is the account it actually reached.
A creation template exists and its prefix does not match
A template set up for prod covers repositories beginning with prod/ and nothing else, so a push to staging/api gets no repository and this error. In our experience this is the surprising one, because the team knows create-on-push is configured and does not know it is scoped by prefix.
The job can push but cannot create
A pipeline written to create the repository on demand fails at the create call instead, with an access error rather than this one, when its role carries only the documented push permissions. The AWS push policy grants the layer and image actions and the authorization token, not repository creation.
How to fix it
Create the repository before the first push
- Create it once with
aws ecr create-repositoryin the correct region, or in your infrastructure tool. - Confirm it from the job with
aws ecr describe-repositoriesand the name. - Keep the name in one variable that both the tag and the create call read.
aws ecr create-repository --repository-name api --region us-east-1
aws ecr describe-repositories --repository-names api --region us-east-1 \
--query "repositories[0].repositoryUri" --output textAdd a repository creation template if you want create-on-push
Define the template with the prefix your services use and CREATE_ON_PUSH among its applied-for actions, so the first push of a new service makes the repository with the settings you chose. Use ROOT as the prefix to cover every repository that has no more specific template.
aws ecr create-repository-creation-template \
--prefix prod \
--applied-for CREATE_ON_PUSH \
--image-tag-mutability MUTABLE \
--region us-east-1Give the job the permission the fix needs
The documented push policy covers uploading layers and putting an image. A job that creates repositories needs ecr:CreateRepository as well, and a template that applies tags or a KMS key needs a repository creation role for ECR to assume. Grant the create action on a narrow resource rather than on every repository in the account.
{
"Effect": "Allow",
"Action": ["ecr:CreateRepository", "ecr:DescribeRepositories"],
"Resource": "arn:aws:ecr:us-east-1:123456789012:repository/*"
}Fail early instead of failing at the push
A push is the end of a build, so this error costs the whole build before it appears. Check the repository at the start of the job, when the failure costs seconds, and say which repository, account and region were expected.
- name: Repository must exist
run: |
aws ecr describe-repositories --repository-names "$REPO" --region "$AWS_REGION" \
|| { echo "::error::no ECR repository $REPO in $AWS_REGION"; exit 1; }The registry URL says which account and which region it looked in
The host is <account>.dkr.ecr.<region> followed by amazonaws.com, so a push carries the account and the region inside the image reference. A repository that exists in us-east-1 is genuinely absent from eu-west-1, and a repository in the shared services account is absent from the account your workflow assumed a role into. Both read as "repository does not exist" because, from where the push landed, that is true.
In a GitHub Actions job using OIDC, the account in the reference and the account behind the role have to agree. Print the caller identity next to the reference once, and this whole class of confusion goes away.
- uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::123456789012:role/gha-push
aws-region: us-east-1
- run: |
aws sts get-caller-identity --query Account --output text
echo "pushing to: $IMAGE"Create it in the job, or own it in infrastructure
A guard step in the pipeline is the fastest fix and it is idempotent: describe the repository, and create it only when the describe fails. It needs an IAM action the standard push policy does not carry, which is the part teams miss. The AWS push policy lists the layer and image actions plus ecr:GetAuthorizationToken, and nothing that creates a repository.
If your repositories carry lifecycle policies, tags, scanning settings or KMS keys, put them in Terraform instead and let the pipeline fail loudly when one is missing. A repository created by a push inherits whatever the template says, and a repository created ad hoc by a CLI call inherits the account defaults, which is how registries end up with images nobody ever expires.
REPO=api
aws ecr describe-repositories --repository-names "$REPO" --region us-east-1 \
--query "repositories[0].repositoryUri" --output text \
|| aws ecr create-repository --repository-name "$REPO" --region us-east-1 \
--image-scanning-configuration scanOnPush=trueWhat the runner does about it
Nothing, and no runner should. This failure is a statement about your registry, not about the machine the job ran on: the push reached ECR, authenticated, and asked for a repository that is not there. A retry on a bigger runner, a different image or a warmer cache changes none of it.
It is also the reason this page carries no reproduction. Our harness runs failures on a Latchkey latchkey-small runner and records the log, and a real ECR push needs AWS credentials, so there is nothing here we could honestly record. The pages in this cluster that did reproduce say so in their own log captions.
How to prevent it
- Provision ECR repositories as infrastructure, so a first deploy never races a create call.
- Keep the account and region in one place the workflow reads, not in a copied string.
- If you rely on create-on-push, check the template prefix covers every namespace you push to.
- Check the repository exists at the start of the job rather than at the push.
Frequently asked questions
Does ECR create a repository automatically when you push?
Why does the push say the repository does not exist when I can see it in the console?
aws sts get-caller-identity inside the same job.What IAM permissions does a job need to create the repository itself?
ecr:PutImage, ecr:BatchGetImage and ecr:GetAuthorizationToken; creating a repository needs ecr:CreateRepository too, and describing one needs ecr:DescribeRepositories. A template that sets tags or a KMS key also needs a repository creation role.Should I create ECR repositories in Terraform or in the CI pipeline?
Related guides
References
- AWS: pushing a Docker image to an Amazon ECR private repository
- AWS: repository creation templates, including create on push
- AWS: IAM permissions for pushing an image
- aws/containers-roadmap#1299: push without creating the repository first
- Docker documentation
- Docker build cache
- GitHub Actions documentation