Ben Muller
12/04/2025, 5:50 AMMarvin
12/04/2025, 5:50 AMMarvin
12/04/2025, 5:54 AMflow.from_source(...).deploy(...) clones a real git repository onto the worker with a .git directory. If cloning succeeds, commands like git rev-parse should work from anywhere under that tree.
- The “fatal: not a git repository (or any of the parent directories): .git” message usually means something in your code or dependencies is calling git from a directory that isn’t inside the cloned repo, or the code was packaged/installed without the .git metadata.
To help you quickly, could you share:
1) Your Prefect version (2.x or 3.x)
2) How you’re deploying:
- Prefect 3.x: are you using flow.from_source(...) with a Git URL, or passing a GitRepository(...) with credentials?
- Prefect 2.x: are you using the GitHub storage block or another storage?
3) The exact stack trace around the error and a snippet of your deployment definition (or CLI you used)
4) Your worker type (AWS ECS, EC2, etc.) and the container image you’re running
Common causes and quick checks:
- Git not installed in the worker image
- If you’re using a custom image, make sure git is installed. Otherwise git calls will fail (often with “git: not found”, but sometimes tools swallow that and show the generic fatal error).
- Code or dependencies expect a git repo at runtime
- Tools like setuptools_scm, versioneer, or any code that runs git (e.g., git describe) will fail if your code was installed from a wheel/zip or if the working directory isn’t within the clone.
- If this is your case and you’re on Prefect 2.x with GitHub storage, note that it downloads a zip without .git. In 3.x, switch to from_source(...) to guarantee .git is present, or configure your package to not require git at runtime (e.g., setuptools_scm fallback via SETUPTOOLS_SCM_PRETEND_VERSION).
- Running git from the wrong directory
- If your code `chdir`s, containers use a non-default working dir, or a subprocess runs elsewhere, git will complain. Log os.getcwd() at the point of failure to confirm.
- Partial/corrupted clone
- Rare, but network issues can leave a broken .git directory. In 3.x, Prefect retries by re-cloning automatically; still, if you have a shared volume, clear the destination and retry.
Recommended setup for Prefect 3.x with GitHub (ensures .git exists and auth is correct):
from prefect import flow
from prefect.runner.storage import GitRepository
from prefect_github.credentials import GitHubCredentials
@flow
def my_flow():
...
creds = GitHubCredentials.load("my-gh-creds")
my_flow.from_source(
source=GitRepository(
url="<https://github.com/OWNER/REPO.git>",
branch="main",
credentials=creds,
include_submodules=False,
),
entrypoint="path/to/flow_file.py:my_flow",
).deploy(
name="aws-ecs-deployment",
work_pool_name="my-aws-ecs-pool",
job_variables={
"image": "prefecthq/prefect:3.0-python3.11"
# ensure your image has git installed if you’re using a custom base
},
)
Helpful diagnostics:
- Temporarily set PREFECT_LOGGING_LEVEL=DEBUG on the worker to see the git clone/pull commands in logs.
- Log os.getcwd() and __file__ where the error happens to confirm you’re under the cloned repo.
- If you use setuptools_scm or similar, try setting SETUPTOOLS_SCM_PRETEND_VERSION=0.0 to test whether the error disappears.
If you can share the items above (version, deployment snippet, worker type/image, and the stack trace/log lines around the error), I’ll zero in on the exact fix.Ben Muller
12/04/2025, 6:08 AM{'prefect.deployments.steps.git_clone': {'branch': 'main', 'repository': '<https://github.com/org/flows>', 'credentials': '{{ prefect.blocks.github-credentials.pat }}'}}
That is my deployment
I am using ecs and trying to clone the code into my container through the pull step in the deployment. prefect 3.x
the worker uses the "prefecthq/prefect:3-latest" imageBen Muller
12/04/2025, 6:08 AMMarvin
12/04/2025, 6:08 AMMarvin
12/04/2025, 6:09 AMPrefect version:
Environment (Cloud/Self-hosted):
Worker/Work pool/Infra:
Command or code used:
Error/traceback (full):
Run/deployment link (if available):
Expected vs actual behavior:
Recent changes (if any):Ben Muller
12/04/2025, 6:10 AM{'prefect.deployments.steps.git_clone': {'branch': 'main', 'repository': '<https://github.com/org/flows>', 'credentials': '{{ prefect.blocks.github-credentials.pat }}'}}
That is my deployment
I am using ecs and trying to clone the code into my container through the pull step in the deployment. prefect 3.x
the worker uses the "prefecthq/prefect:3-latest" image (edited)Marvin
12/04/2025, 6:10 AMMarvin
12/04/2025, 6:16 AMgit_clone step runs inside your task container and requires git to be installed. The prefecthq/prefect:3-latest image already includes git, so that’s fine.
- When you pass a github-credentials block, the runtime needs the prefect-github package so Prefect can load that block type and format the URL with your token. If your ECS image doesn’t have prefect-github, you’ll typically see errors like “Could not import block type GitHubCredentials” or “No module named prefect_github”.
Two ways to make this work:
Option A: Keep using the GitHub credentials block
- Ensure your worker image has prefect-github installed (either bake it into the image or install at startup).
- Bake into image:
FROM prefecthq/prefect:3-latest
RUN pip install --no-cache-dir prefect-github
- Or, if you rely on the Prefect image’s startup behavior, set an env var in your ECS task definition/container:
EXTRA_PIP_PACKAGES=prefect-github
- Then your prefect.yaml can look like:
deployments:
- name: my-flow
entrypoint: flows/my_flow.py:my_flow
pull:
- prefect.deployments.steps.git_clone:
repository: <https://github.com/org/flows.git>
branch: main
credentials: "{{ prefect.blocks.github-credentials.pat }}"
Option B: Use a Secret block with access_token (no extra package needed)
- Store your PAT in a Secret block and reference it:
deployments:
- name: my-flow
entrypoint: flows/my_flow.py:my_flow
pull:
- prefect.deployments.steps.git_clone:
repository: <https://github.com/org/flows.git>
branch: main
access_token: "{{ prefect.blocks.secret.github-pat }}"
Notes and gotchas:
- Make sure the repository URL is not wrapped in angle brackets in your YAML (Slack adds them in messages): use <https://github.com/org/flows.git> (the .git suffix is optional but fine).
- The repo is cloned into the container’s current working directory (in the Prefect image, that’s /opt/prefect). The local folder name is derived from the repo (and branch, if specified).
- If you use submodules, add include_submodules: true and ensure the same credentials work for submodules.
- If you’re using the credentials block, double-check the block name: pat in {{ prefect.blocks.github-credentials.pat }} must match the exact block name you created.
If it’s still failing, could you share the exact error from the run logs? Common ones:
- ModuleNotFoundError for prefect_github → install prefect-github (Option A) or switch to access_token (Option B)
- fatal: could not read Username → token/permissions issue; confirm the PAT scopes and block reference
- git: command not found → custom image missing git
Happy to look at the specific traceback and your prefect.yaml snippet if you can paste them.Ben Muller
12/04/2025, 6:25 AMfatal: not a git repository (or any of the parent directories): .git therre is nothign else provided and the flow stays in a Pending state, so it is very hard to debugMarvin
12/04/2025, 6:25 AMMarvin
12/04/2025, 6:28 AMgit_clone pull step, this most often happens if:
- The target directory already exists from a previous run (or name collision) but does not contain a .git folder
- The working directory isn’t what you expect, so git commands run in the wrong place
Quick fixes you can try:
1) Force a clean working directory before clone
- Use set_working_directory to a fresh path (e.g., /tmp/prefect-work) and optionally clear it first so the clone step starts clean.
- Give the clone step an id, and add a short diagnostics script to prove where we cloned and that it’s a git repo.
Example prefect.yaml pull section:
pull:
- prefect.deployments.steps.run_shell_script:
id: prep
script: |
rm -rf /tmp/prefect-work
mkdir -p /tmp/prefect-work
- prefect.deployments.steps.set_working_directory:
directory: /tmp/prefect-work
- prefect.deployments.steps.git_clone:
id: clone
repository: <https://github.com/org/flows.git>
branch: main
# EITHER use a credentials block (requires prefect-github in the image)...
# credentials: "{{ prefect.blocks.github-credentials.pat }}"
# ...OR use a Secret (no extra package required):
# access_token: "{{ prefect.blocks.secret.github-pat }}"
- prefect.deployments.steps.run_shell_script:
directory: "{{ clone.directory }}"
script: |
echo "CWD:"
pwd
echo "Repo top-level:"
git rev-parse --show-toplevel
echo "Tree:"
ls -la
2) Double-check the repo URL in your YAML
- Don’t include Slack’s angle brackets. It should be <https://github.com/org/flows.git> (or without .git) — not <https://...>.
- Make sure branch: main exists in that repo.
3) If you’re using a GitHub credentials block
- Ensure your ECS image has prefect-github installed. Without it, Prefect can’t load/format the block type at runtime.
- Bake it in or install via env var:
# Dockerfile
FROM prefecthq/prefect:3-latest
RUN pip install --no-cache-dir prefect-github
or set in the ECS task/container env:
EXTRA_PIP_PACKAGES=prefect-github
- Alternatively, switch to access_token: "{{ prefect.blocks.secret.github-pat }}" to avoid the extra package.
4) Get more visibility while it’s “hard to debug”
- Add that final run_shell_script step (above) to print pwd, .git presence, and a short tree — those stdout lines will show up in your container logs.
- Make sure your ECS task’s CloudWatch log group is configured and you’re looking at the container’s stdout/stderr.
- If helpful, temporarily add:
- prefect.deployments.steps.run_shell_script:
script: |
echo "Worker CWD before clone:"
pwd
echo "Contents:"
ls -la
Why this happens
- git_clone clones into the current working directory. If a folder with the derived name already exists but isn’t a git repo (no .git), any subsequent git commands (fetch/pull/checkout) will error with “not a git repository”.
- Using a dedicated clean directory (e.g., /tmp/prefect-work) avoids collisions with any pre-existing folders in the image or from prior runs.
If this still fails after trying the clean working directory, please share:
- Your updated pull: section (sanitized)
- Whether you’re using credentials: or access_token:
- The ECS container logs from the run_shell_script diagnostics step
We’ll get you unstuck quickly with those details.Ben Muller
12/04/2025, 9:23 PM-------------------------------------------------------------
resource "aws_ecs_task_definition" "worker" {
family = "${var.cluster_name}-worker"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = var.worker_cpu
memory = var.worker_memory
execution_role_arn = aws_iam_role.execution_role.arn
task_role_arn = aws_iam_role.task_role.arn
container_definitions = jsonencode([
{
name = "worker"
image = var.worker_image
command = [
"/bin/sh",
"-c",
"prefect worker start --pool ${var.prefect_work_pool} --type ecs"
]
secrets = [
{
name = "PREFECT_API_KEY"
valueFrom = aws_ssm_parameter.api_key.arn
},
{
name = "PREFECT_API_URL"
valueFrom = aws_ssm_parameter.api_url.arn
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = aws_cloudwatch_log_group.prefect.name
"awslogs-region" = data.aws_region.current.id
"awslogs-stream-prefix" = "ecs"
}
}
environment = [
for key, value in var.worker_environment : {
name = key
value = value
}
]
}
])
tags = var.tags
}Marvin
12/04/2025, 9:23 PMMarvin
12/04/2025, 9:27 PMcommand = [
"/bin/sh",
"-c",
"prefect worker start --pool ${var.prefect_work_pool}"
]
2) Ensure your worker image has the AWS integration installed
- The ECS worker type lives in prefect-aws. If it’s missing, the worker won’t start for an ECS pool.
- Your image should include:
pip install "prefect[aws]"
# or
pip install prefect-aws
- Quick check:
python -c "from prefect_aws.workers.ecs_worker import ECSWorker; print('OK')"
3) Your “secrets” are SSM parameters — the execution role must read them
- Because you’re using ECS container “secrets” with SSM Parameter Store, the task’s execution role must allow:
- ssm:GetParameters (and kms:Decrypt if parameters are KMS-encrypted)
- Without these, PREFECT_API_KEY/URL won’t be injected and the worker will fail to connect to Prefect.
- Add a policy like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:GetParameters",
"ssm:GetParameter"
],
"Resource": "arn:aws:ssm:REGION:ACCOUNT:parameter/your-path/*"
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": "arn:aws:kms:REGION:ACCOUNT:key/KEY-ID"
}
]
}
4) Verify the work pool exists, is type ecs, and is unpaused
- From anywhere with the Prefect CLI:
prefect work-pool view ${var.prefect_work_pool}
# Type should be "ecs" and the pool should be unpaused
5) Make sure the worker’s task role has the ECS/IAM permissions it needs to submit runs
- Common minimum set (tune to your environment):
- ecs:RunTask, ecs:RegisterTaskDefinition, ecs:DescribeTaskDefinition, ecs:DescribeTasks, ecs:StopTask, ecs:TagResource
- iam:PassRole (to pass the task and execution roles you reference)
- ec2:DescribeVpcs, ec2:DescribeSubnets (for Fargate networking)
- logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents (for CloudWatch log setup)
- Sample policy reference: Prefect sample ECS worker policy
6) CloudWatch logs config
- Since you set logConfiguration in the task definition, ensure the execution role has logs permissions (CreateLogGroup/CreateLogStream/PutLogEvents) for the specified log group and region.
Quick triage steps
- Get the exact error from your worker task logs in CloudWatch — that will pinpoint whether it’s:
- an “unknown option” (due to --type),
- a missing package (prefect-aws not installed),
- missing API creds (SSM permissions issue),
- or an AWS permission error (ecsRunTask/iamPassRole/etc.).
- Run the image locally to confirm the container can start a worker:
docker run --rm \
-e PREFECT_API_URL=<your-url> \
-e PREFECT_API_KEY=<your-key> \
<your-image> \
prefect worker start --pool ${var.prefect_work_pool}
- Turn on debug logs for more detail:
PREFECT_LOGGING_LEVEL=DEBUG
If you can paste the first 30–50 lines of the worker container logs (especially the error at startup), I can pinpoint which of the above is hitting you.
Helpful docs
- ECS worker guide: Prefect ECS integration
- Example IAM policy: Worker policy exampleBen Muller
12/04/2025, 9:29 PMfatal: not a git repository (or any of the parent directories): .git this is what I am trying to solve!Marvin
12/04/2025, 9:29 PMMarvin
12/04/2025, 9:33 PMgit rev-parse --abbrev-ref HEAD
- and sometimes git config --get remote.origin.url
- When the container’s working directory is not a git repo, git prints:
- fatal: not a git repository (or any of the parent directories): .git
- Prefect catches the non‑zero exit and proceeds (so it’s harmless), but git still writes that “fatal” line to stderr, which shows up in your worker logs.
This message is noisy but not the root cause of flows not starting. Still, if you want to eliminate it, here are practical ways:
Ways to silence the git message
- Initialize an empty repo in the worker’s working directory before starting the worker:
- In your ECS task command:
command = [
"/bin/sh",
"-c",
"git -C /app init -q || true; prefect worker start --pool ${var.prefect_work_pool}"
]
Replace /app with the actual working dir if different. This makes git rev-parse succeed and removes the fatal line.
- Or change the working directory to a path where you’ve done a git init (same effect).
- Alternatively, rebuild your image to include that one-time git init -q in the image at the directory you run the worker from.
Important note
- That git message by itself does not block flow runs. If flows still aren’t starting after we silence it, there’s a separate blocker. Common ones in ECS:
- Worker started against the wrong pool type (pool must be type ecs)
- Missing prefect-aws in the worker image (install prefect[aws])
- IAM permissions (ecs:RunTask, ecs:RegisterTaskDefinition, iam:PassRole, ec2:DescribeVpcs/Subnets, logs:*)
- SSM/KMS permissions for your secrets (so PREFECT_API_KEY/URL actually get injected)
- Missing VPC/subnet config for Fargate
If you can share the 30–50 lines around the first occurrence of that fatal message (and your Prefect version in the worker image), I’ll pinpoint whether anything else is failing right after it.