<@ULVA73B9P> The flows deployed in the managed poo...
# ask-marvin
m
@Marvin The flows deployed in the managed pool started crashing with error. There was no changes made recently Error: Failed to clone repository with exit code 128.
m
thought for 236.6 seconds
Thanks for flagging this — sorry your runs started crashing. Exit code 128 from “git clone” almost always means auth or reachability. In Prefect 3.x managed work pools (Prefect-hosted), the runtime environment does not have your SSH keys, so cloning private repos must use HTTPS with a token provided via deployment pull steps. A few quick confirmations that often explain “no code changes” but sudden failures: - Personal Access Token (PAT) expired, got revoked, or lost org access (e.g., SSO/2FA enforcement or repo permission change) - Repo renamed/transferred/archived, branch deleted, or a pinned commit SHA no longer exists - Fine-grained PAT lost repository permission - Private submodules were added or updated but token doesn’t have access to them - Temporary GitHub outage or rate limits (unauthenticated limit is low) Could you share: - Whether the repo is private and which provider (GitHub/GitLab/Bitbucket)? - Your deployment’s
prefect.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:
Copy code
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):
Copy code
from prefect.blocks.system import Secret
  Secret(value="ghp_...").save("github-token", overwrite=True)
- Reference it in `prefect.yaml`:
Copy code
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:
Copy code
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.
m
@Marvin yaml code:
Copy code
definitions:
    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
Copy code
#!/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 screen
m
thought for 57.3 seconds
Thanks for sharing the YAML and script — that helps a lot. I see two likely culprits for “Failed to clone repository with exit code 128” in a Managed Work Pool: 1) The credentials block type isn’t available at clone time in the managed image - Your pull step passes a GitLabCredentials block:
Copy code
credentials: "{{ 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:
Copy code
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:
Copy code
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:
Copy code
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.
m
@Marvin repo dont have submodules, the gitlab.example.com is not publicly reachable. The PAt status its new with all the required permissions. Why would it start crashing if there was nothing changed recently , as it was running till friday
m
thought for 249.0 seconds
Thanks for the added detail — this explains the behavior. Key point: your GitLab is not publicly reachable. Prefect’s Managed Work Pool runs your code in Prefect-hosted infrastructure on the public Internet. Those runs cannot reach private/internal endpoints (no VPN, no private routes). If your repo is only accessible on your internal network, a managed pool won’t be able to clone it — token or not. Why it “suddenly” started failing if nothing changed - Most common: earlier successful runs were executed by a self-hosted worker inside your network (e.g., a Process/Docker/K8s pool), then that worker stopped or became unavailable, and the Managed pool picked up runs. Managed runs can’t reach your internal GitLab and fail with exit code 128. - Other possibilities outside your code: - Your firewall/DNS changed on Friday (blocking public egress to gitlab.example.com). - The work queue routing changed so a different pool/worker started executing your runs. How to confirm - Open a successful pre-Friday run and a failing run in the Prefect UI and compare the “Worker”/“Infrastructure” info. If the successful ones show a self-hosted worker and the failing ones show “Managed”, that’s the change. - You can also temporarily replace the first pull step with a quick connectivity probe to see what the managed environment can reach:
Copy code
pull:
    - 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:
Copy code
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:
Copy code
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:
Copy code
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:
Copy code
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 secrets
If you can check a pre-Friday successful run’s “Worker” and share what pool/worker ran it, I can give you exact steps to migrate the deployment to that pool or set up a new self-hosted one that will restore connectivity.
m
@Marvin my mistake the gitlab repo is publicly accessible
m
thought for 35.9 seconds
Got it — if the repo is public, managed should be able to clone it without credentials. A few things jump out that can cause exit code 128 here: Most likely issues - Angle brackets in your YAML/script: Your snippets show repository and git config values inside <...>. Those angle brackets are Slack’s link formatting; if they made it into your actual files, git treats them as part of the URL and fails. - Wrong step path: Use prefect.deployments.steps.pull.git_clone (not prefect.deployments.steps.git_clone). - Branch mismatch: If the dev branch was renamed/deleted or protected recently, git clone -b dev will fail with exit 128. Immediate fixes - Use the fully-qualified pull step and remove credentials for a public repo. Also remove any < > around URLs. - Keep your script for installing deps as is, but fix the git config line to not include < >. Working example
Copy code
pull:
  - 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):
Copy code
#!/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