ECS Fargate task stopped unexpectedly: diagnosing container exits
Fix ECS Fargate tasks that keep stopping with Essential container exited, OutOfMemoryError, or CannotPullContainerError by identifying the root cause in stopped task metadata and CloudWatch logs.
This runbook covers the most frequent ECS Fargate task failures. For ongoing container management, see CloudOps Maintenance. For a real-world migration example, read our EC2 to ECS with Fargate case study.
Symptoms
Tasks are being stopped and replaced continuously. The ECS service events show:
# Check stopped task reason
aws ecs describe-tasks \
--cluster my-cluster \
--tasks $(aws ecs list-tasks --cluster my-cluster \
--service-name my-service --desired-status STOPPED \
--query 'taskArns[0]' --output text) \
--query 'tasks[0].{reason:stoppedReason,status:lastStatus,stopCode:stopCode}'
# Common outputs:
# "Essential container in task exited"
# "Task stopped by: OutOfMemoryError: Container killed due to memory usage"
# "CannotPullContainerError: pull image manifest has been retried 5 time(s)"
# Check service events for patterns
aws ecs describe-services \
--cluster my-cluster \
--services my-service \
--query 'services[0].events[:10].[createdAt,message]' \
--output table
You may also see the service oscillating between desired count and zero running tasks, or a high “stopped tasks” count in the ECS console.
Cause
ECS Fargate tasks stop for three primary reasons:
1. Out of Memory (OOMKill): The container exceeds its configured memory hard limit. Fargate kills the container immediately with no graceful shutdown. This is common when memory limits are set too close to actual usage, or when the application has memory leaks.
2. Essential container exited: The main container process crashed (non-zero exit code) or exited cleanly (exit code 0 but the task definition expects it to run indefinitely). Often caused by unhandled exceptions, missing environment variables, or failed health checks that trigger container replacement.
3. CannotPullContainerError: Fargate cannot pull the container image from the registry. This happens when ECR permissions are misconfigured, the image tag does not exist, or the VPC lacks a NAT Gateway / VPC endpoint for ECR access.
Fix
A) Out of Memory: increase memory limits:
# Check actual memory usage before the kill
aws logs filter-log-events \
--log-group-name /ecs/my-service \
--filter-pattern "memory" \
--start-time $(date -d '1 hour ago' +%s000) \
--query 'events[*].message'
# Check Container Insights for peak memory (if enabled)
aws cloudwatch get-metric-statistics \
--namespace ECS/ContainerInsights \
--metric-name MemoryUtilized \
--dimensions Name=ServiceName,Value=my-service \
Name=ClusterName,Value=my-cluster \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 60 --statistics Maximum \
--query 'Datapoints | sort_by(@, &Timestamp) | [-5:]'
# Update task definition with higher memory
# Rule of thumb: set hard limit to 1.5x observed peak
aws ecs register-task-definition \
--cli-input-json file://task-definition.json
# Then update the service to use the new task definition revision
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--task-definition my-service:NEW_REVISION
B) Essential container exited: check logs and health checks:
# Get the exit code of the stopped container
aws ecs describe-tasks \
--cluster my-cluster \
--tasks <TASK_ARN> \
--query 'tasks[0].containers[*].{name:name,exitCode:exitCode,reason:reason}'
# Check CloudWatch logs for crash reason
aws logs tail /ecs/my-service --since 30m --format short | tail -50
# If health check is killing the container, review the health check config:
# - Ensure the health check endpoint returns 200 within the timeout
# - Increase startPeriod for slow-starting applications (default: 0s)
# - Common fix: set startPeriod to 60-120s for Java/Spring apps
# Check environment variables are properly set
aws ecs describe-task-definition \
--task-definition my-service \
--query 'taskDefinition.containerDefinitions[0].environment'
C) CannotPullContainerError: fix image access:
# Verify the image exists in ECR
aws ecr describe-images \
--repository-name my-service \
--image-ids imageTag=latest \
--query 'imageDetails[0].imagePushedAt'
# Check task execution role has ECR permissions
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/ecsTaskExecutionRole \
--action-names ecr:GetDownloadUrlForLayer ecr:BatchGetImage \
--query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'
# If using private subnets, verify VPC endpoints or NAT Gateway exist
aws ec2 describe-vpc-endpoints \
--filters "Name=service-name,Values=com.amazonaws.eu-west-1.ecr.dkr" \
--query 'VpcEndpoints[*].{VpcId:VpcId,State:State}'
Prevention: Set memory soft limit (memoryReservation) to actual expected usage and hard limit to 1.5x peak. Configure health check startPeriod generously for slow-starting applications. Pin image tags to specific digests in production rather than using latest.
Verification
# 1. Check tasks are running and stable
aws ecs describe-services \
--cluster my-cluster \
--services my-service \
--query 'services[0].{running:runningCount,desired:desiredCount,pending:pendingCount}'
# Expected: running == desired, pending == 0
# 2. Verify no recent task stops
aws ecs list-tasks --cluster my-cluster \
--service-name my-service --desired-status STOPPED \
--query 'taskArns | length(@)'
# Expected: 0 or only old tasks
# 3. Check service events for stability (no recent restarts)
aws ecs describe-services \
--cluster my-cluster \
--services my-service \
--query 'services[0].events[:5].message'
# Expected: "has reached a steady state" message
# 4. Verify health check passing
aws elbv2 describe-target-health \
--target-group-arn <TARGET_GROUP_ARN> \
--query 'TargetHealthDescriptions[*].{Target:Target.Id,Health:TargetHealth.State}'
# Expected: all targets "healthy"
If the service maintains steady state for 10+ minutes with no stopped tasks, the issue is resolved. Monitor CloudWatch alarms for task count drops over the next 24 hours.
Frequently asked questions about ECS Fargate task stops
What does "Essential container in task exited" mean on ECS Fargate?
essential in your task definition stopped running, so ECS stopped the entire task. A task has at least one essential container, and when any of them exits - whether it crashed with a non-zero exit code or exited cleanly with code 0 - ECS treats the whole task as failed and replaces it. The message itself does not tell you why the container exited; it only tells you which outcome triggered the task stop. To find the cause, pull the container exit code with aws ecs describe-tasks --query 'tasks[0].containers[*].{name:name,exitCode:exitCode,reason:reason}' and read the CloudWatch logs for the window just before the stop.
What does "Essential container in task exited" with exit code 1 mean?
aws logs tail /ecs/my-service --since 30m --format short to see the actual stack trace, then confirm every required environment variable is present in the task definition. Exit code 0 with the same message means the opposite: the process ran to completion and exited cleanly, but the task definition expects a long-running service, so fix the command to stay in the foreground.
How do I tell an OOMKill apart from an essential container exit?
stoppedReason on the stopped task. An out-of-memory kill reports "OutOfMemoryError: Container killed due to memory usage" and the container exit code is typically 137 (128 + SIGKILL), because Fargate terminates the process immediately with no graceful shutdown. A plain "Essential container in task exited" without the OOM wording is an application-level exit, and the exit code tells you which kind - 1 for a crash, 0 for a clean exit the task did not expect. If you see 137, raise the memory hard limit to about 1.5x observed peak rather than chasing the application code; if you see 1, the fix is in the application or its environment, not the memory limit.
Why does my ECS Fargate task fail with CannotPullContainerError?
ecr:GetDownloadUrlForLayer and ecr:BatchGetImage permissions, an image tag that does not exist in the registry, or a task in private subnets with no route to ECR - no NAT Gateway and no VPC endpoints for ecr.dkr, ecr.api, and S3. Verify the image exists with aws ecr describe-images, simulate the role permissions with aws iam simulate-principal-policy, and confirm the network path with aws ec2 describe-vpc-endpoints. Unlike an essential-container exit, this failure happens at pull time, not at runtime.
Every stopped task means degraded service for your users. ECS silently replaces failed tasks, which masks the problem: your service appears “running” while users experience intermittent 502 errors and timeouts. Without proper health checks and alerting on task stop events, these failures can persist for days before anyone notices the pattern.
ECS tasks crashing in production?
Book a free 30-minute call. We'll review your task definitions and health check configuration to stabilise your services.