Madushan Pathirana
10/01/2025, 9:46 AMMarvin
10/01/2025, 9:46 AMMarvin
10/01/2025, 9:55 AMprefect flow-run execute --flow-run-id <id>
- For this to succeed, the container image must have:
- Python and the Prefect CLI installed (e.g., pip install prefect>=3)
- The command must be run directly (i.e., your container ENTRYPOINT must not hijack/modify the args)
Why exit code 2 is common with pre-existing task definitions
- When you provide a task definition ARN, Prefect uses that definition as-is and overrides the container’s command and environment at run time. Your logs confirm this:
- “Skipping task definition construction since a task definition ARN is provided.”
- “The following job variable references in the task definition template will be ignored: cpu, container_name, memory, image, family”
- If your task definition sets an ENTRYPOINT (e.g., ["python","-m","something"]), ECS will combine ENTRYPOINT + overridden COMMAND. That often produces an invalid invocation like:
- python -m something prefect flow-run execute --flow-run-id ...
which typically exits with code 2.
- If your image does not contain the Prefect CLI, you’ll usually see exit code 127 (“command not found”) instead — so in your case, an entrypoint/command conflict is the most likely culprit.
Immediate fixes to try
1) Remove or neutralize the container ENTRYPOINT in the task definition
- Prefer an empty entrypoint so Prefect’s command runs as-is.
- Example Dockerfile base:
FROM python:3.11-slim
RUN pip install --no-cache-dir "prefect>=3" "prefect-aws"
ENTRYPOINT []
- If you must keep an entrypoint like /bin/sh -lc, ensure the command override is a single shell string that runs prefect correctly.
2) Ensure Prefect is installed and on PATH in the image
- Locally or in a test ECS run:
docker run --rm <your-image> prefect --version
docker run --rm <your-image> prefect flow-run execute --help
3) Confirm the Prefect API is reachable from ECS tasks
- Since you’re running Prefect Server on a single EC2 instance, your ECS tasks (EC2 launch type) must be able to connect to it over your VPC:
- Set PREFECT_API_URL to the reachable address from the ECS task (typically http//<your ec2 private ip>4200/api).
- Open the security group(s) so the ECS task ENI can reach port 4200 on the Prefect EC2 host.
- Bind the server to 0.0.0.0, not just localhost.
- In Prefect Server (self-hosted), PREFECT_API_KEY is not required.
4) Enable/log CloudWatch logs and stream them to Prefect
- In your task definition’s container, use awslogs logging:
- logConfiguration with awslogs driver, a log group, and region.
- Ensure the task execution role has permissions for logs:CreateLogGroup/Stream and logs:PutLogEvents.
- In your ECS work pool’s base job template, enable:
- stream_task_logs: true
- Then you’ll see container logs in the Prefect UI for the run (super helpful to confirm entrypoint/command issues).
5) Double-check the container that Prefect targets
- When a taskDefinitionArn is provided, Prefect ignores template fields like cpu, memory, image, family, and container_name (as your logs note).
- Prefect will override the command/env on the container from the task definition; if you have multiple containers, ensure the one that should run the Prefect command is the primary/first container or be the only container.
- Your logs show the container name ‘data-science-prefect-sync’ exited — confirm that’s the container in which Prefect should run.
Targeted checklist for your environment (ECS EC2 + single EC2 hosting Prefect)Marvin
10/01/2025, 9:55 AMPREFECT_API_URL=http://<prefect-ec2-private-ip>:4200/api configured via the work pool template or worker defaults.
- Task definition:
- Container has Prefect installed.
- ENTRYPOINT is empty (or compatible).
- awslogs is configured.
If you want a low-friction POC path
- Temporarily remove the task definition ARN and let Prefect build the task definition from the base job template. That removes entrypoint/override ambiguity. Once it works, re-introduce your ARN with a known-good container config.
What I need from you to pinpoint the cause
- CloudWatch logs from the failing ECS task’s container (first 50–100 lines).
- The container section of your ECS task definition (ENTRYPOINT, COMMAND, logConfiguration).
- Your ECS work pool base job template (especially if stream_task_logs is set and how task_definition_arn is specified).
- The exact PREFECT_API_URL value used by the worker/pool.
Docs for reference
- Prefect ECS guide
- AWS ECS ENTRYPOINT and COMMAND
Once you share the task’s CloudWatch logs and task definition snippet, I can confirm if it’s the entrypoint/command clash or something else (e.g., API connectivity).Madushan Pathirana
10/01/2025, 9:59 AMOctober 2025, 15:26
╭─ Commands ───────────────────────────────────────────────────────────────────╮
data-science-prefect-sync
1 October 2025, 15:26
│ version Get the current Prefect version and integration │
data-science-prefect-sync
1 October 2025, 15:26
│ information. │
data-science-prefect-sync
1 October 2025, 15:26
│ init Initialize a new deployment configuration recipe. │
data-science-prefect-sync
1 October 2025, 15:26
│ deploy Create a deployment to deploy a flow from this │
data-science-prefect-sync
1 October 2025, 15:26
│ project. │
data-science-prefect-sync
1 October 2025, 15:26
│ transfer Transfer resources from one Prefect profile to │
data-science-prefect-sync
1 October 2025, 15:26
│ another. │
data-science-prefect-sync
1 October 2025, 15:26
│ artifact Inspect and delete artifacts. │
data-science-prefect-sync
1 October 2025, 15:26
│ block Manage blocks. │
data-science-prefect-sync
1 October 2025, 15:26
│ cloud Authenticate and interact with Prefect Cloud │
data-science-prefect-sync
1 October 2025, 15:26
│ shell Serve and watch shell commands as Prefect flows. │
data-science-prefect-sync
1 October 2025, 15:26
│ concurrency-limit Manage task-level concurrency limits. │
data-science-prefect-sync
1 October 2025, 15:26
│ config View and set Prefect profiles. │
data-science-prefect-sync
1 October 2025, 15:26
│ dashboard Commands for interacting with the Prefect UI. │
data-science-prefect-sync
1 October 2025, 15:26
│ deployment Manage deployments. │
data-science-prefect-sync
1 October 2025, 15:26
│ dev Internal Prefect development. │
data-science-prefect-sync
1 October 2025, 15:26
│ events Stream events. │
data-science-prefect-sync
1 October 2025, 15:26
│ flow View and serve flows. │
data-science-prefect-sync
1 October 2025, 15:26
│ flow-run Interact with flow runs. │
data-science-prefect-sync
1 October 2025, 15:26
│ global-concurrency-limit Manage global concurrency limits. │
data-science-prefect-sync
1 October 2025, 15:26
│ profile Select and manage Prefect profiles. │
data-science-prefect-sync
1 October 2025, 15:26
│ server Start a Prefect server instance and interact with │
data-science-prefect-sync
1 October 2025, 15:26
│ the database │
data-science-prefect-sync
1 October 2025, 15:26
│ task Work with task scheduling. │
data-science-prefect-sync
1 October 2025, 15:26
│ variable Manage variables. │
data-science-prefect-sync
1 October 2025, 15:26
│ work-pool Manage work pools. │
data-science-prefect-sync
1 October 2025, 15:26
│ work-queue Manage work queues. │
data-science-prefect-sync
1 October 2025, 15:26
│ worker Start and interact with workers. │
data-science-prefect-sync
1 October 2025, 15:26
│ task-run View and inspect task runs. │
data-science-prefect-sync
1 October 2025, 15:26
│ automation Manage automations. │
data-science-prefect-sync
1 October 2025, 15:26
╰──────────────────────────────────────────────────────────────────────────────╯
data-science-prefect-sync
1 October 2025, 15:26
╭─ Options ────────────────────────────────────────────────────────────────────╮
data-science-prefect-sync
1 October 2025, 15:26
│ --version -v Display the current version. │
data-science-prefect-sync
1 October 2025, 15:26
│ --profile -p TEXT Select a profile for this CLI │
data-science-prefect-sync
1 October 2025, 15:26
│ run. │
data-science-prefect-sync
1 October 2025, 15:26
│ --prompt --no-prompt Force toggle prompts for this │
data-science-prefect-sync
1 October 2025, 15:26
│ CLI run. │
data-science-prefect-sync
1 October 2025, 15:26
│ [default: (from │
data-science-prefect-sync
1 October 2025, 15:26
│ PREFECT_CLI_PROMPT)] │
data-science-prefect-sync
1 October 2025, 15:26
│ --install-completion Install completion for the │
data-science-prefect-sync
1 October 2025, 15:26
│ current shell. │
data-science-prefect-sync
1 October 2025, 15:26
│ --show-completion Show completion for the │
data-science-prefect-sync
1 October 2025, 15:26
│ current shell, to copy it or │
data-science-prefect-sync
1 October 2025, 15:26
│ customize the installation. │
data-science-prefect-sync
1 October 2025, 15:26
│ --help Show this message and exit. │
data-science-prefect-sync
1 October 2025, 15:26
╰──────────────────────────────────────────────────────────────────────────────╯
data-science-prefect-sync
1 October 2025, 15:26
data-science-prefect-sync
1 October 2025, 15:26
Usage: prefect [OPTIONS] COMMAND [ARGS]...
data-science-prefect-sync
1 October 2025, 15:26Marvin
10/01/2025, 9:59 AMOctober 2025 15 26 ╭─ Commands ───────────────────────────────────────────────────────────────────╮ data-science-prefect-sync 1 October 2025 15 26 │ version Get the current Prefect version and integration │ data-science-prefect-sync 1 October 2025 15 26 │ information │ data-science-prefect-sync 1 October 2025 15 26 │ init Initialize a new deployment configuration recipe │ data-science-prefect-sync 1 October 2025 15 26 │ deploy Create a deployment to deploy a flow from this │ data-science-prefect-sync 1 October 2025 15 26 │ project │ data-science-prefect-sync 1 October 2025 15 26 │ transfer Transfer resources from one Prefect profile to │ data-science-prefect-sync 1 October 2025 15 26 │ another │ data-science-prefect-sync 1 October 2025 15 26 │ artifact Inspect and delete artifacts │ data-science-prefect-sync 1 October 2025 15 26 │ block Manage blocks │ data-science-prefect-sync 1 October 2025 15 26 │ cloud Authenticate and interact with Prefect Cloud │ data-science-prefect-sync 1 October 2025 15 26 │ shell Serve and watch shell commands as Prefect flows │ data-science-prefect-sync 1 October 2025 15 26 │ concurrency-limit Manage task-level concurrency limits │ data-science-prefect-sync 1 October 2025 15 26 │ config View and set Prefect profiles │ data-science-prefect-sync 1 October 2025 15 26 │ dashboard Commands for interacting with the Prefect UI │ data-science-prefect-sync 1 October 2025 15 26 │ deployment Manage deployments │ data-science-prefect-sync 1 October 2025 15 26 │ dev Internal Prefect development │ data-science-prefect-sync 1 October 2025 15 26 │ events Stream events │ data-science-prefect-sync 1 October 2025 15 26 │ flow View and serve flows │ data-science-prefect-sync 1 October 2025 15 26 │ flow-run Interact with flow runs │ data-science-prefect-sync 1 October 2025 15 26 │ global-concurrency-limit Manage global concurrency limits │ data-science-prefect-sync 1 October 2025 15 26 │ profile Select and manage Prefect profiles │ data-science-prefect-sync 1 October 2025 15 26 │ server Start a Prefect server instance and interact with │ data-science-prefect-sync 1 October 2025 15 26 │ the database │ data-science-prefect-sync 1 October 2025 15 26 │ task Work with task scheduling │ data-science-prefect-sync 1 October 2025 15 26 │ variable Manage variables │ data-science-prefect-sync 1 October 2025 15 26 │ work-pool Manage work pools │ data-science-prefect-sync 1 October 2025 15 26 │ work-queue Manage work queues │ data-science-prefect-sync 1 October 2025 15 26 │ worker Start and interact with workers │ data-science-prefect-sync 1 October 2025 15 26 │ task-run View and inspect task runs │ data-science-prefect-sync 1 October 2025 15 26 │ automation Manage automations │ data-science-prefect-sync 1 October 2025 15 26 ╰──────────────────────────────────────────────────────────────────────────────╯ data-science-prefect-sync 1 October 2025 15 26 ╭─ Options ────────────────────────────────────────────────────────────────────╮ data-science-prefect-sync 1 October 2025 15 26 │ --version -v Display the current version │ data-science-prefect-sync 1 October 2025 15 26 │ --profile -p TEXT Select a profile for this CLI │ data-science-prefect-sync 1 October 2025 15 26 │ run │ data-science-prefect-sync 1 October 2025 15 26 │ --prompt --no-prompt Force toggle prompts for this │ data-science-prefect-sync 1 October 2025 15 26 │ CLI run │ data-science-prefect-sync 1 October 2025 15 26 │ [default (from │ data-science-prefect-sync 1 October 2025 15 26Madushan Pathirana
10/01/2025, 11:06 AM1 October 2025, 16:26
│ --prompt --no-prompt Force toggle prompts for this │
data-science-prefect-sync
1 October 2025, 16:26
│ CLI run. │
data-science-prefect-sync
1 October 2025, 16:26
│ [default: (from │
data-science-prefect-sync
1 October 2025, 16:26
│ PREFECT_CLI_PROMPT)] │
data-science-prefect-sync
1 October 2025, 16:26
│ --install-completion Install completion for the │
data-science-prefect-sync
1 October 2025, 16:26
│ current shell. │
data-science-prefect-sync
1 October 2025, 16:26
│ --show-completion Show completion for the │
data-science-prefect-sync
1 October 2025, 16:26
│ current shell, to copy it or │
data-science-prefect-sync
1 October 2025, 16:26
│ customize the installation. │
data-science-prefect-sync
1 October 2025, 16:26
│ --help Show this message and exit. │
data-science-prefect-sync
1 October 2025, 16:26
╰──────────────────────────────────────────────────────────────────────────────╯
data-science-prefect-sync
1 October 2025, 16:26
data-science-prefect-sync
1 October 2025, 16:26
Usage: prefect [OPTIONS] COMMAND [ARGS]...
data-science-prefect-sync
1 October 2025, 16:26Marvin
10/01/2025, 11:06 AMMarvin
10/01/2025, 11:08 AMprefect (with no subcommand). That matches the exit code 2 you saw and points to an ENTRYPOINT/COMMAND combination issue in your ECS task definition.
What’s happening
- Prefect 3.x runs your flow via:
prefect flow-run execute --flow-run-id <id>
- When you use a pre-existing task definition ARN, Prefect overrides the container’s command (and env) at runtime. Your worker logs confirm that it ignores job template fields like cpu, memory, image, family, and container_name when an ARN is provided.
- If your task definition sets an ENTRYPOINT like ["/bin/sh","-c"] or a shell script that doesn’t pass arguments through, ECS will combine it with Prefect’s command array. With sh -c, the first element of the array is treated as the whole command string and subsequent elements are treated as $0, $1, etc. The result is only prefect runs — which prints help and exits, causing your crash.
How to fix it
Pick one of these patterns:
1) No shell entrypoint (recommended)
- Make sure your image has Prefect installed and leave ENTRYPOINT empty so ECS runs the command Prefect supplies verbatim.
- Example Dockerfile:
FROM python:3.11-slim
RUN pip install --no-cache-dir "prefect>=3" "prefect-aws"
# IMPORTANT: do not set a shell entrypoint; let Prefect pass the command
ENTRYPOINT []
- In your ECS task definition container:
- Do not specify command (Prefect will supply it).
- Keep entryPoint empty (or unset).
2) Wrapper entrypoint that forwards args
- If you must use an entrypoint (e.g., to do bootstrapping), ensure it forwards the command Prefect provides:
#!/usr/bin/env sh
set -e
# ... any setup you need ...
exec "$@" # This is critical: passes Prefect’s command through
- Dockerfile:
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
- Do not hardcode prefect in the entrypoint or you’ll get the same help output again.
Other checks to make this work smoothly
- Prefect installed in the image:
docker run --rm <your-image> prefect --version
docker run --rm <your-image> prefect flow-run execute --help
- Prefect API connectivity (you’re self-hosting Prefect Server on an EC2):
- Set PREFECT_API_URL to something the ECS task can reach, e.g. http://<prefect-ec2-private-ip>:4200/api.
- Open security groups so the ECS task ENI can reach your Prefect EC2 host on port 4200.
- No PREFECT_API_KEY is needed for Prefect Server (only for Prefect Cloud).
- CloudWatch logs + Prefect log streaming:
- In the task definition container, configure the awslogs driver (region, log group, stream prefix).
- Ensure the task execution role can write to CloudWatch Logs.
- In your ECS work pool’s base job template, enable log streaming so Prefect pulls container logs from CloudWatch during the run.
- Then you’ll see the actual command and any errors directly in the Prefect UI.
- Container selection when using a taskDefinition ARN:
- Prefect can’t change container_name when an ARN is provided (as your logs state), so it will target the container from your task definition. If you have multiple containers, make sure the one intended to run the flow is the first or only container in the definition.
If you share the container section of your task definition (especially entryPoint, command, and logConfiguration), I can confirm the minimal change to stop the help-only behavior.
References:
- Prefect ECS guide
- AWS docs: ENTRYPOINT and COMMANDMadushan Pathirana
10/01/2025, 11:16 AMMarvin
10/01/2025, 11:16 AMMarvin
10/01/2025, 11:19 AMENTRYPOINT ["/opt/prefect/entrypoint.sh"]
That script prepends and runs the Prefect CLI (effectively “prefect …”). When the ECS worker launches a flow run, it overrides the container COMMAND with:
prefect flow-run execute --flow-run-id <id>
ECS combines ENTRYPOINT + COMMAND, so your container ends up running:
/opt/prefect/entrypoint.sh prefect flow-run execute ...
If the entrypoint itself also injects “prefect”, you get:
prefect prefect flow-run execute ...
…which prints the top-level help you saw and exits with code 2.
What to change (pick one)
- Best: neutralize the ENTRYPOINT so Prefect’s command runs verbatim.
- Update your image:
FROM prefecthq/prefect:3-python3.12
RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt asyncpg
ENTRYPOINT []
- Or add a forwarding wrapper that doesn’t prepend “prefect”:
#!/usr/bin/env sh
set -e
exec "$@"
Then:
COPY forward-entrypoint.sh /forward-entrypoint.sh
RUN chmod +x /forward-entrypoint.sh
ENTRYPOINT ["/forward-entrypoint.sh"]
- Alternatively (no image rebuild): set the container’s entryPoint to an empty array in your ECS task definition. An empty entryPoint at the task definition level overrides the image’s ENTRYPOINT and lets the worker’s COMMAND run as-is.
Why this surfaced with a task definition ARN
- When you provide a taskDefinitionArn, Prefect uses that definition and skips building a new one. It still overrides the container’s COMMAND and environment at runtime, but it cannot change the entryPoint. If the image’s entrypoint prepends “prefect”, you get the duplication above.
Quick validation
- Local:
docker run --rm <your-image> prefect flow-run execute --help
If you see help with “No such command 'prefect'”, try neutralizing entrypoint:
docker run --rm --entrypoint "" <your-image> prefect flow-run execute --help
That should print the usage for the execute command, confirming the entrypoint clash.
ECS pool advanced settings checklist for your setup (EC2 launch type)
- task_definition_arn: OK to use, but remember Prefect ignores cpu/memory/image/family/container_name in the base template when an ARN is provided.
- Ensure the task definition has only one container (or the first container is the one you want to run). Prefect will apply command/env overrides to the target container in the TD.
- stream_task_logs: true in the pool template so Prefect pulls logs from CloudWatch into the run UI.
- CloudWatch logConfiguration on the container in the task def (awslogs driver + permissions on the task execution role).
- PREFECT_API_URL must be reachable from ECS tasks (since you’re self-hosting Prefect Server on an EC2 in ap-southeast-1):
- Example: http://<your-prefect-ec2-private-ip>:4200/api
- Security groups: allow the ECS task ENIs to reach port 4200 on the Prefect EC2 host.
- For Prefect Server, you don’t need PREFECT_API_KEY.
- launch_type: EC2, with the right subnets/security groups for your cluster.
- RDS access: make sure the task role/SGs can reach your RDS instance; DB creds can come from Prefect blocks/secrets.
If you’d like, paste your container section from the ECS task definition (entryPoint, command, logConfiguration) and I’ll confirm the minimal change (likely setting entryPoint: [] on that container). References:
- Prefect ECS guide
- AWS: ENTRYPOINT and COMMANDMadushan Pathirana
10/01/2025, 11:29 AMMarvin
10/01/2025, 11:29 AMMarvin
10/01/2025, 11:32 AMarn:aws:ecs:...:task-definition/prefect_my-ecs-pool_...:1 (a Prefect-built TD)
- After applying your Advanced overrides, the final RunTask request had taskDefinition=None
- The worker asserts they must match, so it crashes:
- Task definition ARN mismatch: None != 'arnawsecs:...'
Why this happens
- The Advanced “Task run request overrides” JSON is merged into the request Prefect builds for AWS RunTask.
- If your overrides include "taskDefinition": null (or you replace the whole overrides object), you’ll erase critical fields Prefect sets.
- Result: taskDefinition becomes None and Prefect throws the assertion error you see.
How to fix
1) Remove the taskDefinition key from your Advanced overrides entirely. Prefect will fill it correctly.
2) Avoid replacing Prefect’s overrides wholesale. If you need to add extra container overrides, do it in a way that doesn’t remove Prefect’s container override for the command/env.
- Prefect sets overrides.containerOverrides[<target-container>].command and environment. If you replace overrides with your own, you’ll break the run again.
3) Keep Advanced overrides minimal. Safe examples for EC2:
{
"capacityProviderStrategy": [
{
"capacityProvider": "YourEc2CapacityProvider",
"weight": 1
}
],
"enableExecuteCommand": true,
"propagateTags": "TASK_DEFINITION",
"tags": [
{
"key": "env",
"value": "dev"
}
]
}
Do not include taskDefinition, cluster, or networkConfiguration here if you’ve already set them in the work pool template fields.
Verify your pool config
- Run:
prefect work-pool inspect "my-ecs-pool"
Review the printed `base_job_template`:
- Ensure task_definition_arn is either provided (if you want to reuse an existing TD) or empty (if letting Prefect build it).
- Ensure the Advanced overrides JSON does not contain taskDefinition or a wholesale replacement of overrides.
Reminder about the earlier “prefect help” / exit code 2 issue
- That was caused by your image’s entrypoint + Prefect’s command. If you still use the prefecthq/prefect:3-python3.12 base with ENTRYPOINT ["/opt/prefect/entrypoint.sh"], set the container’s entryPoint to an empty array in your ECS task definition, or rebuild your image with ENTRYPOINT [] or a forwarding wrapper that just exec "$@". Otherwise you’ll get back to help-only output.
If you paste your current “Task run request overrides” JSON from the work pool, I’ll mark exactly what to remove. References:
- Prefect ECS guide
- AWS RunTask APIMadushan Pathirana
10/01/2025, 11:38 AMMarvin
10/01/2025, 11:38 AMMarvin
10/01/2025, 11:39 AMprefect flow-run execute --flow-run-id <id>
Important notes when you supply a taskDefinition ARN:
- Prefect will ignore template fields like cpu, memory, image, family, and container_name from the pool; it will use whatever is in the task definition.
- Prefect will still override the container’s COMMAND and environment at runtime.
- Make sure the task definition’s container has:
- Prefect installed and on PATH
- An entrypoint that doesn’t hijack the command (set entryPoint: [] in the task definition or use an ENTRYPOINT that does exec "$@")
- CloudWatch logs configured if you want streaming logs in Prefect
- Ensure the ECS task can reach your Prefect Server:
- Set PREFECT_API_URL to something reachable from the task, e.g. http://<your-prefect-ec2-private-ip>:4200/api
- Open SGs so the task ENI can reach port 4200 on the Prefect EC2 host
If you’re still iterating, an easier POC path is to remove the ARN and let Prefect build the task definition from the pool template (then add an ARN later once it’s working).
Reference: Prefect ECS guideMadushan Pathirana
10/01/2025, 11:40 AMMarvin
10/01/2025, 11:40 AMMarvin
10/01/2025, 11:41 AM{
"containerDefinitions": [
{
"name": "flow-runner",
"image": "<http://your-account.dkr.ecr.ap-southeast-1.amazonaws.com/your-prefect-image:latest|your-account.dkr.ecr.ap-southeast-1.amazonaws.com/your-prefect-image:latest>",
"essential": true,
"entryPoint": [], // critical: let Prefect’s command run verbatim
"command": [], // leave empty; Prefect will override
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/prefect/flows",
"awslogs-region": "ap-southeast-1",
"awslogs-stream-prefix": "flow"
}
}
}
],
"requiresCompatibilities": ["EC2"],
"networkMode": "awsvpc",
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::<acct>:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::<acct>:role/YourFlowTaskRole"
}
Update your ECS work pool to use that TD ARN
- Set the work pool’s task_definition_arn to the flow-runner TD.
- In “Task run request overrides”, do NOT include taskDefinition (and don’t replace overrides wholesale). If you previously set it and hit “Task definition ARN mismatch: None”, remove it.
- Optional for EC2 capacity: include capacityProviderStrategy in overrides if you use an EC2 capacity provider.
PREFECT_API_URL for Server in ECS
- Point to the Server’s internal endpoint that your tasks can reach:
- If behind an internal ALB: http://your-internal-alb-dns-name/api
- If using ECS service discovery: http://prefect-server.your-namespace.local:4200/api
- Prefect Server does not require PREFECT_API_KEY.
Sanity checks
- Inspect your pool to confirm the effective base job template:
prefect work-pool inspect "<your-ecs-pool-name>"
- Run a tiny test flow to validate the flow-runner TD before moving to real workloads.
- If you still see “prefect” help output or exit code 2, your entrypoint is still intercepting the command — set entryPoint: [] on the container in the TD or rebuild the image with ENTRYPOINT [].
If you share:
- The ARN you currently set on the pool
- The container section of that task definition (entryPoint, command, logConfiguration)
- Your pool’s “Task run request overrides” JSON
…I’ll mark the exact changes to make it work. References: Prefect ECS guide and AWS: ENTRYPOINT vs COMMAND.Madushan Pathirana
10/01/2025, 11:50 AMMarvin
10/01/2025, 11:50 AMMarvin
10/01/2025, 11:50 AMprefect flow-run execute --flow-run-id <id>
What to use instead (recommended):
- Create a dedicated ECS task definition for flow runs, e.g. “prefect-flow-runner”:
- Container image: your image with Prefect + your deps (prefecthq/prefect:3-… works)
- entryPoint: [] (critical so Prefect’s command is not hijacked)
- command: [] (leave empty; Prefect will override)
- Single container only
- awslogs logging configured
- requiresCompatibilities: EC2
- Proper taskRole/executionRole
- Put THAT ARN into the ECS work pool.
Or, easiest POC:
- Leave task_definition_arn blank in the pool and let Prefect build the task definition for you. Once it’s working, you can switch to a pre-created ARN if you want.
Also:
- In “Task run request overrides”, do not set taskDefinition and do not replace overrides wholesale; only add safe fields (e.g., capacityProviderStrategy for EC2).
- Make sure tasks can reach your Prefect Server’s internal endpoint and set PREFECT_API_URL accordingly (e.g., internal ALB DNS or service discovery), no PREFECT_API_KEY needed for Server.
If you share the container section of your current “flow-runner” TD (entryPoint, command, logConfiguration), I’ll confirm it’s ready. Reference: Prefect ECS guideMadushan Pathirana
10/01/2025, 11:59 AMMarvin
10/01/2025, 11:59 AMMarvin
10/01/2025, 12:01 PM{
"family": "prefect-flow-runner",
"networkMode": "awsvpc",
"requiresCompatibilities": ["EC2"],
"executionRoleArn": "arn:aws:iam::REPLACE_ME_AWS_ACCOUNT_ID:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::REPLACE_ME_AWS_ACCOUNT_ID:role/YourFlowTaskRole",
"containerDefinitions": [
{
"name": "flow-runner",
"image": "REPLACE_ME_ECR_OR_DOCKER_IMAGE",
"essential": true,
"entryPoint": [],
"command": [],
"cpu": 256,
"memoryReservation": 512,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/prefect/flows",
"awslogs-region": "ap-southeast-1",
"awslogs-stream-prefix": "flow"
}
},
"environment": [
// Leave Prefect env empty; the worker will inject PREFECT_API_URL (and API key if Cloud)
]
}
]
}
Notes and why this works
- entryPoint: [] is critical. It overrides the image’s ENTRYPOINT (including the Prefect base image’s /opt/prefect/entrypoint.sh) so the worker’s command runs verbatim:
- prefect flow-run execute --flow-run-id <id>
- command: [] must be empty so Prefect can supply the command at run time.
- Single container only. When you provide a taskDefinition ARN, Prefect can’t change container_name — keeping one container ensures overrides hit the right target.
- CPU/memory: small defaults for your POC. You can tune later.
- Logging: awslogs configured so you can stream logs back to Prefect (set stream_task_logs: true in the ECS work pool base job template; ensure task execution role can create/write the log group).
Image options
- You can point image to:
- Your custom image with your dependencies preinstalled, and no ENTRYPOINT (or it’s fine because entryPoint: [] in TD overrides it).
- Or the public Prefect image, e.g. prefecthq/prefect:3-python3.12 (still fine because TD sets entryPoint: []).
What not to use
- Do not use your Prefect Server task definition ARN.
- Do not use your Prefect Worker task definition ARN.
- Use this dedicated “flow-runner” task definition’s ARN in the ECS work pool.
After you register the task definition
- Put the returned ARN into your ECS work pool’s task_definition_arn.
- In the work pool:
- Set your cluster ARN.
- Provide subnets and security groups (awsvpc) that allow the task to reach:
- Your Prefect Server endpoint (internal ALB or service discovery), e.g. http//<internal endpoint>4200/api
- Your RDS instance
- Turn on stream_task_logs: true.
- In Advanced “Task run request overrides”, DO NOT set taskDefinition and do not replace overrides wholesale. If you need EC2 capacity provider, add only:
{
"capacityProviderStrategy": [
{"capacityProvider": "REPLACE_ME_EC2_CAPACITY_PROVIDER", "weight": 1}
]
}
Want me to fill this with your exact ARNs and image? Share:
- executionRoleArn
- taskRoleArn
- the image you’ll use (ECR URI or dockerhub)
- desired log group name (or I’ll keep /ecs/prefect/flows)
…and I’ll hand back a final JSON you can register.Madushan Pathirana
10/01/2025, 12:08 PMMarvin
10/01/2025, 12:08 PMMarvin
10/01/2025, 12:10 PMENTRYPOINT ["/opt/prefect/entrypoint.sh"]
- That script is “Prefect-aware.” If the first argument is not prefect, it prepends prefect and execs. If it is prefect, it just execs as-is.
- The ECS worker (in Prefect 3.x) starts a flow by overriding the container command to:
prefect flow-run execute --flow-run-id <id>
or sometimes just
flow-run execute --flow-run-id <id>
In both cases, the entrypoint handles it correctly and runs the Prefect CLI to execute the flow.
Why using the same image worked for both “server” and “flow-runner”
- Your Prefect Server service likely uses the same image but its ECS service/task definition sets a default command like:
prefect server start
- Your flow runs use an ECS task definition ARN (the older revision) where Prefect overrides the command at runtime to:
prefect flow-run execute --flow-run-id <id>
- Because the Prefect entrypoint script forwards the args properly, both use cases work with the same image. The difference comes from the command that’s set/overridden for each run.
Why it sometimes broke (you saw just the Prefect help and exit code 2)
- That behavior appears when the effective command becomes just prefect with no subcommand.
- The two main ways that can happen are:
- Task run request overrides removed or blanked out the worker’s containerOverrides.command (e.g., by replacing overrides or setting an empty command), so only the entrypoint ran and it saw no arguments.
- A mismatched container selection (e.g., multiple containers in the task definition and Prefect’s overrides didn’t land on the one you expected), leaving the “flow” container with no command override.
Keep it stable
- In your ECS work pool:
- Do not include taskDefinition in “Task run request overrides”.
- Do not replace the entire overrides structure; only add safe fields (e.g., capacityProviderStrategy).
- Prefer a single-container task definition for flow runs so Prefect’s override always targets the right container.
- It’s fine to keep using the Prefect base image with its entrypoint — it is designed for this. Avoid custom entrypoints like /bin/sh -c that can swallow/reshape arguments.
- If you want to decouple server changes from flow execution, create a dedicated “flow-runner” task definition and use that ARN in the pool. It prevents server TD updates from accidentally impacting flow runs.
If you want, share the current “Task run request overrides” JSON and the containerDefinitions from the TD you use for flows; I’ll call out anything that could blank the command or target the wrong container.
Reference: Prefect ECS guideMadushan Pathirana
10/01/2025, 1:06 PMMarvin
10/01/2025, 1:06 PMMarvin
10/01/2025, 1:07 PM{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "<http://ecs-tasks.amazonaws.com|ecs-tasks.amazonaws.com>"
},
"Action": "sts:AssumeRole"
}
]
}
- executionRoleArn should have at least the AWS managed policy:
- AmazonECSTaskExecutionRolePolicy
- This covers ECR pulls, CloudWatch Logs, and ECS Exec. If you’re using private ECR, ensure the usual ECR permissions are present.
- taskRoleArn should have whatever your flow needs (e.g., Secrets Manager/SSM if you use them, S3, etc.). Since your DB creds are stored in Prefect, this may be minimal, but it still needs the proper trust policy above.
3) Don’t override roles in Advanced overrides
- Roles are taken from the task definition. Do not try to set or null them in the work pool’s “Task run request overrides.” If you previously added anything that touches roles, remove it.
4) If you’re using a pre-existing TD ARN in the work pool
- Fix the roles on that task definition and register a new revision; keep using its ARN in the pool.
- If you let Prefect build the TD (no ARN), ensure your ECS work pool base template includes valid role ARNs for the TD it will create, or edit the generated TD afterward.
5) Optional quick test
- Temporarily remove enableExecuteCommand from your overrides (if you set it) to reduce required permissions. If that makes it pass, your execution role is missing SSM “ssmmessages” permissions (included in AmazonECSTaskExecutionRolePolicy).
Common gotchas
- Using a role name instead of an ARN.
- Role exists in a different account.
- Trust policy principal is wrong (must be ecs-tasks.amazonaws.com).
- You copied the Server/Worker service role into the flow-run TD; it might not have the correct trust/policies for tasks.
Links
- AWS: IAM role for ECS task execution (executionRoleArn)
Task execution IAM role
- AWS: Task role for ECS tasks (taskRoleArn)
Task IAM role
- AWS: RunTask API
RunTask
- Prefect ECS guide
Prefect ECS guide
If you paste:
- The TD JSON for the revision Prefect is using (just the role fields + containerDefinitions header),
- The trust policies for both roles,
I’ll point out the exact line to fix.Madushan Pathirana
10/01/2025, 6:22 PMMarvin
10/01/2025, 6:22 PMMarvin
10/01/2025, 6:23 PMprefect flow-run execute ...) runs verbatim.
# Base image with Prefect 3 and Python 3.12
FROM prefecthq/prefect:3-python3.12
# Keep logs unbuffered and pip lean
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
# OS packages you mentioned
RUN apt-get update && \
apt-get install -y --no-install-recommends git curl && \
rm -rf /var/lib/apt/lists/*
# App directory
WORKDIR /opt/prefect/flows
# Python deps first (for better layer caching)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt asyncpg
# If your flows import prefect-aws (S3, ECS blocks, etc), also add:
# RUN pip install --no-cache-dir "prefect-aws>=0.4"
# Copy your flow code (adjust as needed)
# COPY . .
# Critical: no entrypoint so Prefect’s command runs verbatim in ECS
ENTRYPOINT []
# No default CMD; ECS worker will provide the command
Quick local check
- After building:
docker run --rm <your-image> prefect --version
docker run --rm <your-image> prefect flow-run execute --help
- Push the image to ECR and update your task definition’s image to that URI.
Notes
- Your ECS task definition already has "entryPoint": [] and `"command": []`; this Dockerfile mirrors that behavior for safety. Either one (image ENTRYPOINT [] or TD entryPoint: []) is sufficient, but having both won’t hurt.
- Don’t bake PREFECT_API_URL into the image; the ECS worker will inject it at run time.
- Keep a single container in the task definition so Prefect’s overrides target the right container.