CannotPullContainerError: pull image manifest has been retried
Fix ECS CannotPullContainerError: add a NAT or VPC endpoints, grant the execution role ECR access, and check the image tag. Covers Fargate and secrets errors.
CannotPullContainerError: pull image manifest has been retried 5 time(s): failed to resolve ref "123456789012.dkr.ecr.eu
Incident Overview
Fix ECS CannotPullContainerError: add a NAT or VPC endpoints, grant the execution role ECR access, and check the image tag. Covers Fargate and secrets errors.
medium fix·5 min read·4 causes
By Vishvesh Patel·DevOps Engineer·Updated 21 September 2026
CannotPullContainerError: pull image manifest has been retried 5 time(s): failed to resolve ref "123456789012.dkr.ecr.eu-west-1.amazonaws.com/api:1.4.2": failed to do request: Head "https://...": dial tcp 10.0.2.15:443: i/o timeout CannotPullContainerError: ... unexpected status from HEAD request: 403 Forbidden ResourceInitializationError: unable to pull secrets or registry auth
Do this first3 steps
Run these in order. Each one tells you what its output means before you change anything.
• Read the task's stopped reason, which names the real cause
An i/o timeout is a network path problem, a 403 is permissions, and ResourceInitializationError points at the execution role rather than the task role. These three need entirely different fixes.
• Check the execution role, not the task role
The execution role is what the ECS agent uses to pull images and read secrets before your container starts. The task role is what your application uses afterwards. Pull failures are always the execution role.
• Confirm the task has a route to the registry
A task in a private subnet with assignPublicIp DISABLED and no NAT gateway and no VPC endpoints cannot reach ECR at all. This is the single most common cause on Fargate.
aws ecs describe-tasks --cluster prod --tasks arn:aws:ecs:eu-west-1:123456789012:task/prod/abc123 --query 'tasks[0].{stopped:stoppedReason,containers:containers[].reason}'Then: the 4 causes in full
If the steps above did not settle it, these are the causes in the order they are usually responsible. Each section explains why it happens and how to confirm it.
The ECS agent could not fetch the image. Read the stopped reason first, because the three variants have different causes:
aws ecs describe-tasks --cluster prod --tasks <task-arn> \
--query 'tasks[0].{stopped:stoppedReason,containers:containers[].reason}'Cause 1: No route to the registry
The most common on Fargate, and the least obvious because nothing is misconfigured in an IAM sense.
A private subnet with no public IP needs either a NAT gateway or VPC endpoints. Without one, the pull times out.
Option A: NAT gateway. Simple, and it has an hourly charge plus data processing costs.
No 0.0.0.0/0 route via a NAT gateway means no outbound path.
Option B: VPC endpoints. Cheaper at volume and keeps traffic off the internet. ECR needs three, and missing any one of them fails:
The S3 gateway endpoint is required because ECR stores image layers in S3. People create the two ECR endpoints, see the pull still fail, and conclude endpoints do not work. Add S3.
You will also want a logs endpoint for CloudWatch, or the task starts and then cannot ship logs.
The interface endpoints need a security group allowing 443 from the task's security group, and private DNS enabled.
assignPublicIp: ENABLED in a public subnet with an internet gateway also works, and is the quickest way to prove the diagnosis.
aws ecs describe-services --cluster prod --services api \ --query 'services[0].networkConfiguration.awsvpcConfiguration'
Cause 2: Execution role permissions
This is the distinction that catches everyone. There are two roles:
A pull failure is always the execution role.
Attach the managed policy:
For a cross-account ECR pull, the repository policy on the other side must also allow it:
ecr:GetAuthorizationToken is account-level and stays in the puller's IAM policy, not the repository policy.
aws ecs describe-task-definition --task-definition api \
--query 'taskDefinition.{exec:executionRoleArn,task:taskRoleArn}'Cause 3: ResourceInitializationError on secrets
The task definition references a Secrets Manager secret or SSM parameter and the execution role cannot read it:
kms:Decrypt is needed for a secret encrypted with a customer-managed key, and is frequently forgotten.
The same endpoint problem applies: a private subnet needs a secretsmanager or ssm VPC endpoint too.
ResourceInitializationError: unable to pull secrets or registry auth
Cause 4: The tag does not exist
A pipeline that pushes :latest and deploys :${SHA} fails here. Note also that ECR image tag immutability, if enabled, causes the push to fail silently in some pipelines, so the tag is simply never created.
aws ecr describe-images --repository-name api \ --query 'imageDetails[].imageTags' --output text
Fargate platform version
On Fargate, pulls go out through the task ENI, so everything above applies to the task's own subnet and security group, not the cluster's. A security group with no outbound rules blocks the pull; the default allows all egress, so this only bites where someone has locked egress down.
A checklist
Frequently Asked Questions
What is the difference between the ECS task role and the execution role?
The execution role belongs to the ECS agent and is used before your container starts, to pull the image from ECR, fetch secrets referenced in the task definition, and create log streams. The task role is assumed by your application code once it is running, for whatever AWS APIs it calls. Any failure during image pull or secret retrieval is therefore an execution role problem, and adding permissions to the task role will have no effect at all.
Why does my Fargate task fail to pull from ECR in a private subnet?
Because a private subnet with assignPublicIp: DISABLED has no route to ECR unless you provide one. Either add a NAT gateway with a 0.0.0.0/0 route, or create VPC endpoints. The endpoint route catches people because ECR needs three: interface endpoints for ecr.api and ecr.dkr, plus an S3 gateway endpoint, since ECR stores the actual image layers in S3. Creating only the two ECR endpoints leaves the layer download with nowhere to go.
Why do I need an S3 endpoint to pull from ECR?
ECR's API handles authentication and manifests, but the image layers themselves are stored in S3 and downloaded directly from there. So a task in a private subnet can authenticate to ECR successfully through the interface endpoints and then fail while fetching layers, which produces a pull error that looks like the endpoints are not working. The S3 gateway endpoint is free and attaches to a route table rather than a subnet, so it is worth adding as a matter of course.
What does ResourceInitializationError mean?
It occurs before your container starts, while the ECS agent is preparing the task, and almost always means it could not fetch something the task definition references. The usual cause is the execution role lacking secretsmanager:GetSecretValue or ssm:GetParameters for a referenced secret, often together with a missing kms:Decrypt when the secret uses a customer-managed key. In a private subnet it can also mean there is no VPC endpoint for Secrets Manager or SSM, so the request has no route.
How do I quickly test whether it is a network problem or a permissions problem?
Temporarily move the task to a public subnet with assignPublicIp: ENABLED. If the pull then succeeds, the problem is the network path and you need a NAT gateway or VPC endpoints. If it still fails with a 403 or a denial, it is IAM, and the execution role is the thing to look at. This one change separates the two causes in a couple of minutes and avoids a long investigation in the wrong direction.
Reference and practice
Learn the underlying concept
Other AWS errors
Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.
Get notified about new tutorials and features.
• Roadmaps
• Interview Prep
• Certifications
• Company
© 2026 DevOpsLesson. All rights reserved.
Need to practice this scenario?
Simulate this error condition and practice recovery commands safely in our in-browser terminal.