Medwin David
10/26/2025, 2:15 AMMarvin
10/26/2025, 2:15 AMMarvin
10/26/2025, 2:19 AMprefect.yaml pull section (redact secrets)
- Whether you’re pinning branch or commit_sha
- If your repo uses submodules
- A link/run ID for a failed flow run
Recommended checks and fixes
1) Verify the token still works and has the right scopes
- If GitHub, ensure the PAT hasn’t expired and is authorized for the org (SSO).
- Test locally:
curl -H "Authorization: Bearer <TOKEN>" <https://api.github.com/user>
You should get your user JSON. If 401/403, fix the token.
2) Use HTTPS token auth in your deployment pull step (managed pools cannot use SSH)
- Create a Secret block with your PAT (via UI or Python):
from prefect.blocks.system import Secret
Secret(value="ghp_...").save("github-token", overwrite=True)
- Reference it in `prefect.yaml`:
pull:
- prefect.deployments.steps.pull.git_clone:
repository: "<https://github.com/ORG/REPO>"
branch: "main" # or remove if you use commit_sha
include_submodules: false # set true if you use them
access_token: "{{ prefect.blocks.secret.github-token }}"
Notes:
- access_token can read from a Secret block reference
- If you use submodules, set include_submodules: true and ensure the token has access to those repos as well
3) If you pin a commit SHA, confirm it still exists
- In prefect.yaml, if you use commit_sha, verify the commit wasn’t force-pushed away.
4) Check for provider changes/outages
- If this started suddenly for all runs, confirm provider status (e.g., GitHub status) and org policy changes (e.g., new 2FA/SSO enforcement).
5) Alternative to Git clone (if this is urgent)
- You can store flow code in object storage and pull it at runtime:
pull:
- prefect.deployments.steps.pull.pull_from_remote_storage:
- path: "<s3://my-bucket/path/to/project.tar.gz>"
See docs for details.
Helpful docs
- Store flow code for deployments
- prefect.yaml reference
- Pull steps API
- Store and use secrets
If you paste your prefect.yaml pull section (redacting the token) and confirm whether the repo is private and uses submodules, I can pinpoint the exact fix.Medwin David
10/26/2025, 2:28 AMdefinitions:
work_pools:
managed-pool: &managed-pool
name: managed-pool
work_queue_name: nexus
pull:
- prefect.deployments.steps.git_clone:
id: git-clone
repository: "<https://gitlab.example.com/example/data-analytics/nexa.git>"
branch: "dev"
credentials: "{{ prefect.blocks.gitlab-credentials.gitlab-integration }}"
- prefect.deployments.steps.run_shell_script:
directory: "{{ git-clone.directory }}"
stream_output: true
script: bash prefect-build-project.sh
below is the prefect-build-project.sh
#!/usr/bin/env sh
echo ">>> Installing prefect-gitlab to fetch GitLab PAT"
pip install prefect-gitlab
# enable installing of private repos
echo "================= Building project using UV"
GITLAB_PAT=$(
python - <<EOF
from prefect_gitlab import GitLabCredentials
# Load the secret block by its name
gitlab_creds = GitLabCredentials.load("gitlab-integration")
gitlab = gitlab_creds.get_client()
# Retrieve and print the secret value
print(gitlab_creds.token.get_secret_value())
EOF
) || {
printf '%s\n' "Failed to get the secret value" >&2
exit 1
}
echo "================= Setting gitconfig"
git config --global url."<https://oauth2>:${GITLAB_PAT}@gitlab.example.com".insteadOf <ssh://git@gitlab.example.com>
echo "================= Running using UV to build"
uv pip install --system . || {
printf '%s\n' "UV sync failed in directory: $(pwd) --> gitlab pat: ${GITLAB_PAT}" >&2
exit 1
}
# add a random path to /app/ to error out and print logs to screenMarvin
10/26/2025, 2:28 AMMarvin
10/26/2025, 2:29 AMcredentials: "{{ prefect.blocks.gitlab-credentials.gitlab-integration }}"
- Managed pools use a Prefect-provided image that does NOT have prefect-gitlab installed at the time the pull step runs. If the step can’t deserialize/use that block type, it will fall back to cloning without auth, which results in exit code 128 for a private repo.
- You install prefect-gitlab inside your shell script, but that happens after cloning — too late to help the git_clone step.
2) Token/permission changes (very common)
- GitLab PAT expired/rotated
- Org/SSO/2FA policy changed
- Repo or branch renamed or access lost
- Private submodules added and token doesn’t have access
Recommended fix (works reliably on managed pools)
- Switch the pull step to use a Secret block and pass the token via the access_token parameter. The built-in Secret block requires no extra collection to deserialize.
Example:
pull:
- prefect.deployments.steps.pull.git_clone:
id: git-clone
repository: "<https://gitlab.example.com/example/data-analytics/nexa.git>"
branch: "dev"
# If you use submodules, set this true and ensure the PAT can access them
include_submodules: false
access_token: "{{ prefect.blocks.secret.gitlab-pat }}"
- prefect.deployments.steps.utility.run_shell_script:
directory: "{{ git-clone.directory }}"
stream_output: true
script: bash prefect-build-project.sh
Create/update the Secret block with your PAT:
from prefect.blocks.system import Secret
Secret(value="YOUR_GITLAB_PAT").save("gitlab-pat", overwrite=True)
Why this helps
- Built-in Secret is available without installing any collection, so the token is present at clone time.
- You can still keep prefect-gitlab in your script if you need its client later, but it’s not required for cloning.
Other checks
- Connectivity: Is gitlab.example.com reachable publicly from the Internet? Managed pools cannot reach private/VPN-only hosts. If it’s internal-only, you’ll need a self-hosted worker instead of a managed pool.
- Token validity: Quickly verify the PAT:
curl --header "PRIVATE-TOKEN: <PAT>" <https://gitlab.example.com/api/v4/user>
If this fails (401/403), refresh/re-authorize the token.
- Submodules: If you use them, set include_submodules: true and ensure the PAT has scope/access to those repos.
- Minor path tweak: Using the fully qualified step path under “pull” is the most explicit form:
prefect.deployments.steps.pull.git_clone and prefect.deployments.steps.utility.run_shell_script
Docs
- Store flow code for deployments
- Pull steps API
- Store and use secrets
If you can confirm:
- Whether gitlab.example.com is publicly reachable
- Whether your repo has submodules
- The status of the PAT in GitLab
…I can tailor the exact YAML and next steps.Medwin David
10/26/2025, 2:39 AMMarvin
10/26/2025, 2:39 AMMarvin
10/26/2025, 2:43 AMpull:
- prefect.deployments.steps.utility.run_shell_script:
stream_output: true
script: |
set -x
curl -I <https://gitlab.example.com> || true
getent hosts <http://gitlab.example.com|gitlab.example.com> || true
If you see “Could not resolve host” or timeouts, it’s a reachability issue.
Your current YAML/script notes
- Installing prefect-gitlab in your shell script won’t help the clone step: cloning happens before the script runs. Also, even with a valid token, managed can’t reach your internal GitLab.
- Minor cleanup for future: prefer the fully-qualified step paths:
- prefect.deployments.steps.pull.git_clone
- prefect.deployments.steps.utility.run_shell_script
Paths to resolution
Pick one of these based on your constraints:
1) Run on a self-hosted work pool inside your network (recommended for private GitLab)
- Create a Process/Docker/Kubernetes work pool and start a worker within your network so it can reach gitlab.example.com.
- Point your deployment to that pool/queue. Example worker start:
prefect worker start -p your-internal-pool -q nexus
- This keeps your current git_clone approach intact.
2) Keep Managed, but make code publicly reachable
- Mirror or package your project to public/object storage (e.g., S3/GCS) and pull it at runtime:
pull:
- prefect.deployments.steps.pull.pull_from_remote_storage:
path: "<s3://my-bucket/path/to/project.tar.gz>"
- Or expose your GitLab to the public Internet (or allowlist Prefect’s egress IPs) — if your infosec allows.
3) Keep Managed, but build a code artifact image
- If you switch to a Docker/K8s worker (self-hosted), you can bake your code into an image and avoid runtime cloning altogether.
Small improvement if/when reachability is solved
- Use a built-in Secret block for the token so clone works without needing extra collections:
pull:
- prefect.deployments.steps.pull.git_clone:
repository: "<https://gitlab.example.com/example/data-analytics/nexa.git>"
branch: "dev"
access_token: "{{ prefect.blocks.secret.gitlab-pat }}"
And create the Secret:
from prefect.blocks.system import Secret
Secret(value="YOUR_GITLAB_PAT").save("gitlab-pat", overwrite=True)
Docs
- Store flow code for deployments
- Pull steps API
- Store and use secretsMarvin
10/26/2025, 2:43 AMMedwin David
10/26/2025, 3:05 AMMarvin
10/26/2025, 3:05 AMMarvin
10/26/2025, 3:05 AMpull:
- prefect.deployments.steps.utility.run_shell_script:
stream_output: true
script: |
set -ex
git --version
# Check that the repo and branch resolve from the managed environment
git ls-remote --heads <https://gitlab.example.com/example/data-analytics/nexa.git> dev
- prefect.deployments.steps.pull.git_clone:
id: git-clone
repository: "<https://gitlab.example.com/example/data-analytics/nexa.git>"
branch: "dev"
# no credentials needed for public repo
- prefect.deployments.steps.utility.run_shell_script:
directory: "{{ git-clone.directory }}"
stream_output: true
script: bash prefect-build-project.sh
And update your script (remove angle brackets):
#!/usr/bin/env sh
set -e
echo ">>> Installing prefect-gitlab to fetch GitLab PAT"
pip install prefect-gitlab
# If you still need PAT for private pip installs later, keep this:
GITLAB_PAT=$(
python - <<EOF
from prefect_gitlab import GitLabCredentials
gitlab_creds = GitLabCredentials.load("gitlab-integration")
print(gitlab_creds.token.get_secret_value())
EOF
) || {
printf '%s\n' "Failed to get the secret value" >&2
exit 1
}
# Only needed if you install private repos via git+ssh later; fix URL patterns and drop <>
echo "================= Setting gitconfig"
git config --global url."<https://oauth2:${GITLAB_PAT}@gitlab.example.com>".insteadOf <ssh://git@gitlab.example.com>
echo "================= Running using UV to build"
uv pip install --system . || {
printf '%s\n' "UV sync failed in directory: $(pwd)" >&2
exit 1
}
Why it might have “suddenly” broken on Friday
- A small change outside your code could explain it:
- The YAML or script gained angle brackets from a copy/paste via Slack or a wiki (very easy to miss).
- The branch was renamed/protected/deleted.
- You switched the deployment to a managed pool recently or the work queue was re-routed so managed started picking up runs (less likely since the repo is public, but still possible).
- Less common: GitLab rate limiting or transient outage; the ls-remote check above will help confirm quickly.
If it still fails, please share the stderr from the git_clone step logs (e.g., “repository not found”, “remote branch dev not found”, “could not resolve host”, etc.). That message will pinpoint the exact cause.
References
- Store flow code for deployments: docs
- Pull steps API: docs
- prefect.yaml reference: docs
- Secrets: docs