Vander
11/21/2025, 5:13 PMMarvin
11/21/2025, 5:13 PMMarvin
11/21/2025, 5:16 PMconfigure_cloudwatch_logs: true and a valid execution_role_arn).
- Then check the log group/stream in CloudWatch for the failed task.
- Via AWS CLI:
# List log streams (adjust prefix to your pool/deployment)
aws logs describe-log-streams \
--log-group-name prefect \
--log-stream-name-prefix "prefect-logs_"
# Get events from a specific stream
aws logs get_log_events \
--log-group-name prefect \
--log-stream-name "<the-log-stream-name>"
Share the first error in those logs if you can—this pinpoints the cause.
2) Common causes and quick fixes
- Command/entrypoint overrides
- In Prefect 3.x, ECS flow-run containers default to:
python -m prefect.engine <flow_run_id>
If you override command or entryPoint in the task definition or pool, you can break this. Try removing your override so the default runs, or ensure your override still invokes python -m prefect.engine and receives the flow run id (the worker passes it).
- Prefect not installed in the image
- Symptoms: “ModuleNotFoundError: No module named 'prefect'” or “python: not found”
- Fix: Use an image that has Python and Prefect installed (and your code if needed). Sanity-check locally:
docker run --rm your-image:tag python -m prefect.engine --help
- Missing/incorrect Prefect API config
- Symptoms: errors fetching the flow run, auth failures, connection timeouts
- Ensure the container has PREFECT_API_URL and PREFECT_API_KEY. The worker injects these—avoid overriding environment wholesale in your task definition.
- Networking
- Private subnets need NAT for egress so the task can reach Prefect Cloud. Security groups must allow outbound traffic. Lack of egress often shows as timeouts in logs.
- IAM (execution role)
- For CloudWatch logs you need logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents. For ECR images, include ECR pull permissions. Missing permissions can cause the task to fail before your code runs.
- Resources (CPU/Memory)
- OOM or too-low CPU can cause abrupt exits. Try increasing `cpu`/`memory` in the pool configuration and check CloudWatch for OOM indications.
3) Validate your image and config locally
- Verify Prefect is present and Python works:
docker run --rm your-image:tag python -m prefect.engine --help
- If you want to simulate the engine invocation:
docker run --rm \
-e PREFECT_API_URL=<your api url> \
-e PREFECT_API_KEY=<your key> \
-e PREFECT__FLOW_RUN_ID=550e8400-e29b-41d4-a716-446655440000 \
your-image:tag \
python -m prefect.engine 550e8400-e29b-41d4-a716-446655440000
You’ll likely see an error about the flow run ID not existing, which is fine; this just confirms Python/Prefect run inside the image.
4) If you’re not on ECS
- Docker work pool: check docker logs <container_id> for the same first error.
- Kubernetes work pool: kubectl logs <pod-name> -n <namespace> and look for the first error lines.
If you can share:
- Which infrastructure you’re using (ECS/Docker/K8s)
- Whether you’ve overridden the task command/entrypoint
- The first 20–30 lines of your container logs from CloudWatch (or docker/kubectl)
…I can give you a targeted fix.Vander
11/21/2025, 5:23 PMMarvin
11/21/2025, 5:23 PMMarvin
11/21/2025, 5:29 PMfrom prefect.blocks.system import Secret
from prefect.runner.storage import GitRepository
repo = GitRepository(
url="<https://github.com/org/private-repo.git>",
credentials={"access_token": Secret.load("github-token")}
)
flow.from_source(
source=repo,
entrypoint="flows/my_flow.py:my_flow"
).deploy(
name="managed-deploy",
work_pool_name="YOUR-MANAGED-POOL"
)
3) Add missing dependencies (very common)
- Managed installs packages at runtime. If your flow imports pandas, requests, etc., add them to job_variables["pip_packages"].
flow.from_source(...).deploy(
name="managed-deploy",
work_pool_name="YOUR-MANAGED-POOL",
job_variables={
"pip_packages": ["pandas", "requests"],
"env": {"MY_ENV_VAR": "value"}
}
)
- Alternatively, use pull steps in prefect.yaml to install a requirements.txt. If requirements are heavy or have strict pins, test a clean install locally first to ensure it resolves.
4) Ensure required environment variables/secrets are set
- Put non-secret env in job_variables["env"].
- Put secrets in Prefect Blocks and reference them (don’t hardcode).
5) Add temporary debug logging to surface root cause
from prefect import flow
from prefect.logging import get_run_logger
@flow(log_prints=True)
def my_flow():
logger = get_run_logger()
<http://logger.info|logger.info>("Flow starting")
# import your libs here so import errors show up in Prefect logs
import pandas as pd
<http://logger.info|logger.info>(f"Pandas version: {pd.__version__}")
...
6) Test locally before redeploy
- Clone the repo locally, install the same dependencies, and import your flow with the exact entrypoint:
- Does python -c "from flows.my_flow import my_flow; print(my_flow)" work?
- Do imports succeed in a clean environment?
7) Resource constraints
- Managed pools have fixed resources per run. If logs show MemoryError/OOM, consider chunking work or reducing in-memory data size.
If you can share:
- Your deployment snippet (how you call .from_source(...).deploy(...))
- Whether the repo is private and how you’re providing credentials
- The first 20–30 lines from the run’s Logs tab and the State message
…I can pinpoint the exact fix quickly.Vander
11/21/2025, 5:58 PMdeployment_name = "flow_pipeline_dashboard"
work_pool_name = "managed-work-pool"
flow_entrypoint = "main_flow.py:flow_pipeline_dashboard"
deployment_rrule_schedule_string = "DTSTART:20241104T055500Z RRULE:FREQ=WEEKLY;BYDAY=WE"
github_credentials_block = GitHubCredentials.load("github-cred")
with open("requirements.txt", "r", encoding="utf-8") as f:
pip_packages = [line.strip() for line in f if line.strip()]
main_flow = flow.from_source(
source = GitRepository(
url = repository_url,
credentials = github_credentials_block
),
entrypoint = flow_entrypoint,
)
main_flow.deploy(
name = deployment_name,
work_pool_name = work_pool_name,
schedule = RRuleSchedule(
rrule = deployment_rrule_schedule_string,
timezone = "America/Sao_Paulo"
),
job_variables = {"pip_packages": pip_packages,
"stream_output": True,
"image_name": "prefecthq/prefect-client:3-python3.10"
}
)Marvin
11/21/2025, 5:58 PMMarvin
11/21/2025, 5:59 PMjob_variables["pip_packages"]. The pip_packages field expects plain package specs only. If your requirements file contains pip flags like -r, -e, --extra-index-url, -f, etc., the runtime install will fail and the container will exit with code 1.
- Managed work pools don’t support custom images. The image_name you set (prefecthq/prefect-client:3-python3.10) is not used on Managed and can cause confusion. Remove it.
- If your repo is private, ensure the token in your GitHubCredentials block has at least repo scope. If the container can’t fetch code, it will exit quickly with code 1.
- Confirm your entrypoint path main_flow.py:flow_pipeline_dashboard exists at the repo root. A wrong path results in an immediate crash.
What to change in your code
1) Sanitize requirements before passing to pip_packages
This avoids pip flags and comments that break pip install when given as package names.
from pathlib import Path
def read_pip_packages(path="requirements.txt"):
keep = []
for line in Path(path).read_text(encoding="utf-8").splitlines():
s = line.strip()
if not s or s.startswith(("#", "-r", "-e", "--", "-f")):
continue
keep.append(s)
return keep
pip_packages = read_pip_packages("requirements.txt")
2) Remove unsupported job variables for Managed
Only keep what Managed actually uses.
main_flow.deploy(
name=deployment_name,
work_pool_name=work_pool_name,
schedule=RRuleSchedule(
rrule=deployment_rrule_schedule_string,
timezone="America/Sao_Paulo",
),
job_variables={
"pip_packages": pip_packages,
# optional env if your flow needs it
"env": {
"PREFECT_LOGGING_LEVEL": "DEBUG"
}
},
)
3) Optional: include submodules if your repo uses them
from prefect.runner.storage import GitRepository
# ...
source=GitRepository(
url=repository_url,
credentials=github_credentials_block,
include_submodules=True, # only if you use submodules
)
4) Confirm entrypoint path
Make sure main_flow.py is at the repo root and flow_pipeline_dashboard is the exported flow function name in that file.
Extra checks to pinpoint the root cause
- Look at the flow run logs in the Prefect UI. If logs are empty, it often means code fetch or pip install failed. If you do see logs, the first error lines will usually name the missing package or import error.
- If your requirements include packages that build from source (e.g., psycopg2, mysqlclient, prophet), prefer wheels where possible (psycopg2-binary, etc.). Native builds can fail in the managed runtime.
- If the repo is private, verify the GitHubCredentials block token is valid and not expired, with repo scope.
If the issue persists, please share:
- The first 20–30 lines from the flow run’s Logs tab
- Whether your requirements.txt includes any flags like -r, --extra-index-url, -e
- Whether main_flow.py sits at the repo root and exports flow_pipeline_dashboard
With that, I can give you a precise fix.Vander
11/21/2025, 5:59 PMMarvin
11/21/2025, 5:59 PMMarvin
11/21/2025, 6:00 PMmain_flow.py is at the repo root and exports a Prefect @flow named flow_pipeline_dashboard.
- A mismatched file or function name will crash immediately.
- Remove “image” customization for Managed
- Managed doesn’t use custom images. Drop image_name from job_variables. It won’t be used and can cause confusion.
- stream_output isn’t required for Managed; you can remove it as well.
- Sanitize pip_packages (common cause)
- pip_packages must be plain package specs. If your requirements.txt includes flags like -r, -e, --extra-index-url, -f, or comments, the runtime pip install will fail and the container exits with code 1.
- Try this to filter only real packages:
from pathlib import Path
def read_pip_packages(path="requirements.txt"):
keep = []
for line in Path(path).read_text(encoding="utf-8").splitlines():
s = line.strip()
if not s or s.startswith(("#", "-r", "-e", "--", "-f")):
continue
keep.append(s)
return keep
pip_packages = read_pip_packages("requirements.txt")
- Verify packages install in the Prefect runtime image
- Managed uses Prefect’s official runtime. Test a clean install locally to catch wheels/build issues:
docker run --rm -v "$PWD":/app -w /app prefecthq/prefect:3-latest bash -lc "
python -V
pip install --no-cache-dir -r requirements.txt
"
- If this fails, identify the problematic package. Common offenders need system deps (e.g., mysqlclient, prophet, some crypto libs). Prefer wheels or alternatives:
- psycopg2 -> psycopg2-binary
- mysqlclient -> pymysql or mysql-connector-python
- If you truly need system builds, Managed won’t work; use a Docker/Kubernetes pool with a custom image that bakes deps.
- Surface the error in logs
- If your run logs are empty, the failure likely happened during code fetch or pip install. If you do see logs, the first error lines typically name the missing/failed package or an import error.
- You can also force early imports to expose dependency issues:
from prefect import flow
from prefect.logging import get_run_logger
@flow(log_prints=True)
def flow_pipeline_dashboard():
logger = get_run_logger()
<http://logger.info|logger.info>("Flow starting")
import pandas as pd
<http://logger.info|logger.info>(f"Pandas version: {pd.__version__}")
# ...rest of your logic...
Suggested deploy changes
deployment_name = "flow_pipeline_dashboard"
work_pool_name = "managed-work-pool"
flow_entrypoint = "main_flow.py:flow_pipeline_dashboard"
github_credentials_block = GitHubCredentials.load("github-cred")
pip_packages = read_pip_packages("requirements.txt") # use the helper function above
main_flow = flow.from_source(
source=GitRepository(
url=repository_url,
credentials=github_credentials_block,
# include_submodules=True, # only if your repo uses submodules
),
entrypoint=flow_entrypoint,
)
main_flow.deploy(
name=deployment_name,
work_pool_name=work_pool_name,
schedule=RRuleSchedule(
rrule=deployment_rrule_schedule_string,
timezone="America/Sao_Paulo",
),
job_variables={
"pip_packages": pip_packages,
"env": {"PREFECT_LOGGING_LEVEL": "DEBUG"} # optional, helps during debugging
},
)
If the issue persists, please share:
- The first 20–30 lines from the flow run’s Logs tab and the State message
- Whether your requirements.txt contains flags like -r/--extra-index-url/-e
- A quick confirmation that main_flow.py is at the repo root and defines flow_pipeline_dashboard
From there, I can pinpoint the exact dependency or entrypoint issue.Vander
11/21/2025, 6:50 PMMarvin
11/21/2025, 6:50 PMVander
11/21/2025, 6:51 PMMarvin
11/21/2025, 6:51 PMMarvin
11/21/2025, 6:51 PMpip_packages must be plain package specs. Lines like -r, -e ., --extra-index-url, --find-links, and comments will cause failures when passed as “packages”.
What to change now
1) Remove unsupported job variables
- Drop image_name and stream_output from job_variables. Managed won’t use them.
2) Sanitize the requirements you pass to pip_packages
from pathlib import Path
def read_pip_packages(path="requirements.txt"):
keep = []
for line in Path(path).read_text(encoding="utf-8").splitlines():
s = line.strip()
if not s or s.startswith(("#", "-r", "-e", "--", "-f")):
continue
keep.append(s)
return keep
pip_packages = read_pip_packages("requirements.txt")
3) Ensure your pins are compatible with the Managed runtime
- Test with the managed image locally:
docker run --rm -v "$PWD":/app -w /app prefecthq/prefect:3-latest bash -lc "
python -V
pip install --no-cache-dir -r requirements.txt
"
- If this fails, the error output will name the offending package. Typical issues:
- Old pins that don’t have wheels for Python 3.11+ (e.g., numpy/pandas/scipy versions too old)
- Packages that need system libs (e.g., mysqlclient, prophet). Prefer wheel alternatives (psycopg2-binary, mysql-connector-python/pymysql) or move to a Docker/K8s pool with a custom image if you need system deps.
4) If you use a private index or constraints
- Don’t pass flags via pip_packages. Instead set env vars:
job_variables={
"pip_packages": pip_packages,
"env": {
"PIP_INDEX_URL": "<your-index-url>", # if you override the default
"PIP_EXTRA_INDEX_URL": "<your-extra-index-url>", # if you need an extra index
"PIP_TRUSTED_HOST": "<trusted-host>" # if required
}
}
5) If your repo uses submodules
- Add include_submodules=True to GitRepository.
Double-check the basics
- Entry point path is correct (you’ve confirmed).
- The flow function is decorated with @flow and named flow_pipeline_dashboard.
- No early failures in your flow’s imports: you can temporarily add early imports and log versions to surface failures in Prefect logs.
Please share:
- The first 20–30 lines from the failed run’s Logs tab and the State message
- A snippet of your requirements.txt (especially any strict pins or flags like --extra-index-url)
- Whether you rely on packages that compile native code
With that, I can point to the exact package/pin that’s causing the exit code 1 and suggest the right version or workaround.Marvin
11/21/2025, 6:52 PMprefect==3.6.3 at runtime. On Managed, the container already includes Prefect. Reinstalling/downgrading Prefect inside the managed container is a frequent cause of exit code 1 (version conflicts with installed integrations, resolver failures, or mismatches with the managed runtime).
- Fix: remove any prefect (and prefect-client) entries from pip_packages. Let the Managed image’s Prefect drive the run.
2) Integration version mismatches
- You’ve pinned several integrations (prefect-email, prefect-gcp, prefect-github). If they require a different Prefect version than the one in the Managed image, pip may resolve conflicts or fail to install, causing the container to exit.
- After removing the Prefect pin, keep integrations pinned only if you’re sure they’re compatible with the Managed image’s Prefect. Otherwise, either:
- Loosen pins for integrations so pip can resolve a compatible set, or
- Pin to versions you’ve verified work together locally in the Prefect 3-latest image.
Recommended changes
- Don’t pass Prefect to pip_packages; filter it out:
from pathlib import Path
def read_pip_packages(path="requirements.txt"):
keep = []
skip_prefixes = ("#", "-r", "-e", "--", "-f")
for line in Path(path).read_text(encoding="utf-8").splitlines():
s = line.strip()
if not s or s.startswith(skip_prefixes):
continue
# Skip Prefect/core packages; Managed provides Prefect
lower = s.lower()
if lower.startswith("prefect==") or lower == "prefect" or lower.startswith("prefect>") or lower.startswith("prefect<"):
continue
if lower.startswith("prefect-client"):
continue
keep.append(s)
return keep
pip_packages = read_pip_packages("requirements.txt")
- Remove Managed-ignored fields from job_variables
- Managed does not use custom images. Drop image_name.
- stream_output isn’t needed on Managed; you can remove it.
- Keep deployment concise:
main_flow.deploy(
name=deployment_name,
work_pool_name=work_pool_name,
schedule=RRuleSchedule(
rrule=deployment_rrule_schedule_string,
timezone="America/Sao_Paulo"
),
job_variables={
"pip_packages": pip_packages,
"env": {"PREFECT_LOGGING_LEVEL": "DEBUG"} # optional, helps diagnose
}
)
Fast way to confirm the root cause
- Try one run with pip_packages=[] (temporarily). If it succeeds, reintroduce your packages incrementally (minus Prefect) to find the problematic one.
- Optional: test your requirements inside Prefect’s official runtime locally:
docker run --rm -v "$PWD":/app -w /app prefecthq/prefect:3-latest \
bash -lc "python -V && pip install --no-cache-dir -r requirements.txt"
If this fails, the same install will likely fail on Managed.
Also double-check
- Entry point: confirm the repo root has main_flow.py and it defines @flow def flow_pipeline_dashboard(): ....
- If you don’t import/use an integration (e.g., prefect-github) in this flow, consider removing it to minimize resolver work.
If it still crashes after removing prefect==..., please share the first 20–30 lines from the flow run’s Logs tab (and the State message). That will identify exactly which package or import is failing.