<@ULVA73B9P> how to build and deploy from gitlab?
# ask-marvin
o
@Marvin how to build and deploy from gitlab?
m
thought for 218.3 seconds
Great question! Here are the common ways to build and deploy Prefect 3.x flows that live in GitLab, including private repos and CI/CD pipelines. If anything below doesn’t match your setup (public vs. private, worker type, etc.), let me know and I’ll tailor it. Assumptions: - You’re on Prefect 3.x - You want deployments that pull code from GitLab at run time - You’ll run in Prefect Cloud (but this works with a self-hosted server too) Key docs: Prefect GitLab integration 1) Programmatic deployment from a GitLab repo (works for public or private) - Install dependencies:
pip install prefect prefect-gitlab
- For a public repo, you can pass a Git URL directly - For a private repo, use the
prefect-gitlab
integration with a token Public repo example:
Copy code
from prefect.flows import Flow

# Repo is public; Prefect will clone it when running
flow = Flow.from_source(
    source="<https://gitlab.com/<group>/<project>.git>",
    entrypoint="flows/etl.py:etl",
)

# Deploy to a work pool; optionally build/push a container image
flow.deploy(
    name="etl-prod",
    work_pool_name="k8s-pool",  # or docker/ecs/etc.
    # image="<http://registry.gitlab.com/<group>/<project>/prefect:latest|registry.gitlab.com/<group>/<project>/prefect:latest>",
    # build=True,
    # push=True,
)
Private repo example (using prefect-gitlab):
Copy code
import os
from prefect.flows import Flow
from prefect_gitlab.repositories import GitLabRepository
from prefect_gitlab.credentials import GitLabCredentials

repo = GitLabRepository(
    repository="<group>/<project>",       # GitLab path, e.g. "my-group/my-repo"
    reference="main",                     # branch, tag, or commit SHA (optional)
    path="",                              # subdirectory within repo (optional)
    host="<http://gitlab.com|gitlab.com>",                    # or your self-managed host
    credentials=GitLabCredentials(token=os.environ["GITLAB_TOKEN"]),
)

flow = Flow.from_source(
    source=repo,
    entrypoint="flows/etl.py:etl",        # path/to/file.py:flow_function_name
)

flow.deploy(
    name="etl-prod",
    work_pool_name="k8s-pool",
    # image="<http://registry.gitlab.com/<group>/<project>/prefect:latest|registry.gitlab.com/<group>/<project>/prefect:latest>",
    # build=True,
    # push=True,
)
Notes: - You’ll need a GitLab Personal Access Token with at least
read_repository
for private repos. - If you’re building/pushing a Docker image, your token/CI will also need registry permissions. 2) Deploy via CLI in GitLab CI If you prefer CLI, run
prefect deploy
from your GitLab pipeline. This is great when your repo is already checked out by CI. Minimal (no image build) — good for serverless/Kubernetes workers:
Copy code
# .gitlab-ci.yml
image: python:3.11

stages: [deploy]

deploy:
  stage: deploy
  variables:
    PREFECT_API_URL: $PREFECT_API_URL
    PREFECT_API_KEY: $PREFECT_API_KEY
  before_script:
    - pip install -U prefect prefect-gitlab
    - prefect version
    # Optional: create the work pool once (safe to run idempotently)
    - prefect work-pool create "$WORK_POOL" --type kubernetes || true
  script:
    # Run from the project root so entrypoint paths resolve
    - prefect deploy flows/etl.py:etl --name etl-prod --work-pool "$WORK_POOL"
With image build + push to GitLab Container Registry: - Requires Docker-in-Docker or another builder. Below uses DinD. ``` # .gitlab-ci.yml image: docker:24.0 services: - docker:24.0-dind variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" PREFECT_API_URL: $PREFECT_API_URL PREFECT_API_KEY: $PREFECT_API_KEY stages: [deploy] deploy: stage: deploy before_script: - apk add --no-cache py3-pip git - pip install -U prefect prefect-gitlab - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY" # Optional: create the work pool once (docker/k8s/etc.) - prefect work-pool create "$WORK_POOL" --type docker || true script: # Option A: Use a small deploy.py to control image/build/push flags - python - << 'PY'
from prefect.flows import Flow from prefect_gitlab.repositories import GitLabRepository from prefect_gitlab.credentials import GitLabCredentials import os repo = GitLabRepository( repository=os.environ["CI_PROJECT_PATH"], # group/project reference=os.environ.get("CI_COMMIT_SHA", "main"), host=os.environ.get("CI_SERVER_HOST", "gitlab.com"), credentials=GitLabCredentials(token=os.environ["GITLAB_TOKEN"]) ) flow = Flow.from_source( source=repo, entrypoint="flows/etl.py:etl", ) flow.deploy( name="etl-prod", work_pool_name=os.environ["WORK_POOL"], image=os.environ["CI_REGISTRY_IMAGE"] + ":prefect-latest", build=True, push=True, ) PY
Copy code
Why deploy.py? It uses the `Flow.deploy(..., image=..., build=True, push=True)` API which is explicit and version-stable. It also makes it easy to customize per environment without relying on CLI flags.

Environment variables you’ll typically set in GitLab CI/CD settings:
- PREFECT_API_URL, PREFECT_API_KEY (Prefect Cloud/server)
- WORK_POOL (e.g., `k8s-pool` or `docker-pool`)
- GITLAB_TOKEN (for private repos; scope `read_repository`)
- CI_REGISTRY_USER / CI_REGISTRY_PASSWORD (for registry auth; GitLab provides these)
- CI_REGISTRY_IMAGE (GitLab-provided, e.g., <http://registry.gitlab.com/group/project|registry.gitlab.com/group/project>)


One-time setup (if needed)
- Create a work pool (Docker, Kubernetes, etc.). You can do it once locally or in CI:
prefect work-pool create "k8s-pool" --type kubernetes # or prefect work-pool create "docker-pool" --type docker ``` Common gotchas - Token scopes: for cloning private repos use `read_repository`; for pushing images use
write_registry
. - Docker builds: ensure DinD or your org’s builder is available; Prefect’s build step talks to your Docker daemon. - Entrypoint path: use repo-relative
path/to/file.py:flow_func_name
. - Self-managed GitLab: set
host="your.gitlab.host"
in
GitLabRepository
. Would you like me to tailor this to: - public vs. private repo? - your worker type (Docker, Kubernetes, ECS, etc.)? - using CLI flags vs. a
deploy.py
script? - building images or running from prebuilt ones?
o
@Marvin it says OSError OSError: Failed to pull from remote: fatal: repository "myrepository.git" does not exist but i know it does.
m
thought for 69.5 seconds
That error usually means one of these is off: - The repo path/host is wrong (GitLab paths must include the full namespace, e.g., group/subgroup/project) - The repo is private and your token isn’t being used where the clone happens (GitLab returns 404 “does not exist” on auth failures) - You’re pointing at the wrong GitLab host (self-managed vs gitlab.com) - You passed a display name or “myrepository.git” instead of the full namespace path Quick fixes and checks 1) If using Flow.from_source with a Git URL (public repo) - Make sure the full URL includes the namespace:
Copy code
from prefect.flows import Flow

flow = Flow.from_source(
    source="<https://gitlab.com/<group>/<subgroup>/<project>.git>",
    entrypoint="flows/etl.py:etl",
)
2) If the repo is private, use the GitLab integration and a token with read_repository - Do not pass just “myrepository.git”. Provide the namespace path (no .git) and host.
Copy code
import os
from prefect.flows import Flow
from prefect_gitlab.repositories import GitLabRepository
from prefect_gitlab.credentials import GitLabCredentials

repo = GitLabRepository(
    repository="my-group/my-subgroup/my-project",  # full path, no .git
    reference="main",                              # optional
    host="<http://gitlab.com|gitlab.com>",                             # or your self-managed host
    credentials=GitLabCredentials(token=os.environ["GITLAB_TOKEN"]),
)

flow = Flow.from_source(
    source=repo,
    entrypoint="flows/etl.py:etl",
)
3) Verify the environment that’s doing the clone has the token - If the clone happens at runtime (worker pulls code), the token must be available in the worker’s environment (via work pool base job template, Kubernetes/Docker secrets, etc.). - If you’re building an image during deploy (build=True), the token must be available in the CI environment that runs deploy. 4) Sanity test the exact URL and token outside Prefect (from the same environment) - Public:
Copy code
git ls-remote <https://gitlab.com/<group>/<subgroup>/<project>.git>
- Private:
Copy code
git ls-remote <https://oauth2:${GITLAB_TOKEN}@gitlab.com/<group>/<subgroup>/<project>.git>
If this fails, it’s either the path, the host, or the token. Common pitfalls - Using the project’s display name instead of the path. Use the path shown under “Project information -> Details” (e.g., group/subgroup/project). - Including “.git” inside GitLabRepository(repository="..."). Pass the path without .git; Prefect appends it. - Self-managed GitLab not specifying host. Set host="your.gitlab.company". - Missing token or wrong scope (needs at least read_repository). GitLab will return 404 for private repos without valid auth. Docs: Prefect GitLab integration If you can share: - How you’re creating the deployment (code/CLI snippet) - Whether the repo is private and your GitLab host - Where the error occurs (during deploy build or at flow run time) …I can pinpoint the exact fix.
m
thought for 55.3 seconds
Good news: your token and repo are valid. The error suggests Prefect is trying to clone the wrong remote — specifically something like
"myrepository.git"
without the full GitLab namespace/host, or without using your token at clone time. What usually causes that - Repository path missing namespace: needs
group/subgroup/project
(not just
myrepository.git
) - Using
.git
in the
GitLabRepository(repository=...)
field — pass the path without
.git
- Host mismatch: not setting
host="<http://gitlab.com|gitlab.com>"
(or your self-managed host) - Token not present in the environment where the clone actually happens (the worker or the build step), even if it works on your laptop Fixes If you’re using Flow.from_source with a Git URL:
Copy code
from prefect.flows import Flow

flow = Flow.from_source(
    source="<https://gitlab.com/<group>/<subgroup>/<project>.git>",
    entrypoint="flows/etl.py:etl",
)
If you’re using the GitLab integration for a private repo:
Copy code
import os
from prefect.flows import Flow
from prefect_gitlab.repositories import GitLabRepository
from prefect_gitlab.credentials import GitLabCredentials

repo = GitLabRepository(
    repository="<group>/<subgroup>/<project>",  # full namespace, no .git
    reference="main",                           # branch/tag/SHA (optional)
    host="<http://gitlab.com|gitlab.com>",                          # or your self-managed host
    credentials=GitLabCredentials(token=os.environ["GITLAB_TOKEN"]),
)

flow = Flow.from_source(
    source=repo,
    entrypoint="flows/etl.py:etl",
)
Make sure the token is available wherever the clone happens - During deployment image build (
build=True
): token must be set in CI - At flow runtime: token must be set in the worker environment (K8s secret, Docker env, etc.) Quick diagnostics - Turn on logging and Git verbosity where the failure occurs (CI/worker):
Copy code
export PREFECT_LOGGING_LEVEL=DEBUG
export GIT_TRACE=1
export GIT_CURL_VERBOSE=1
This will show the exact remote URL Prefect is trying to clone — if you see
"myrepository.git"
or a host mismatch, that’s the culprit. Docs: Prefect GitLab integration If you can share: - The snippet you use to create the deployment (Flow.from_source or
prefect deploy
command) - Whether the repo is private and your GitLab host - Where the error happens (during image build or at runtime) …I can pinpoint the exact change.
o
@Marvin still trace: built-in: git clone uvd/uvd-workflow-orchestrator-example-prefect -b main --depth 1 /tmp/tmpcklg8bmrprefect fatal: repository 'uvd/uvd-workflow-orchestrator-example-prefect' does not exist although i can acess with PAT from cli
m
thought for 93.9 seconds
Thanks for the trace — that line tells us exactly what’s wrong:
Copy code
built-in: git clone uvd/uvd-workflow-orchestrator-example-prefect -b main --depth 1 /tmp/tmpcklg8bmrprefect
Prefect is trying to clone a remote named
uvd/uvd-workflow-orchestrator-example-prefect
without a host or protocol. Git interprets that like a local path and fails. Your PAT works (you proved with git ls-remote), but Prefect isn’t being told the full remote URL. Fix: provide a full Git URL or use the GitLab integration with host + credentials. Option A — Public repo via full URL
Copy code
from prefect.flows import Flow

flow = Flow.from_source(
    source="<https://gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>",
    entrypoint="flows/etl.py:etl",
)
Option B — Private repo via prefect-gitlab (recommended)
Copy code
import os
from prefect.flows import Flow
from prefect_gitlab.repositories import GitLabRepository
from prefect_gitlab.credentials import GitLabCredentials

repo = GitLabRepository(
    repository="uvd/uvd-workflow-orchestrator-example-prefect",  # full namespace, no .git
    reference="main",                                            # optional
    host="<http://gitlab.com|gitlab.com>",                                           # or your self-managed host
    credentials=GitLabCredentials(token=os.environ["GITLAB_TOKEN"]),
)

flow = Flow.from_source(
    source=repo,
    entrypoint="flows/etl.py:etl",
)
Then deploy as usual:
Copy code
flow.deploy(
    name="etl-prod",
    work_pool_name="your-pool",
    # image="<http://registry.gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect:prefect-latest|registry.gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect:prefect-latest>",
    # build=True,
    # push=True,
)
Important notes - For GitLabRepository, pass
repository="group/subgroup/project"
without
.git
, and set
host="<http://gitlab.com|gitlab.com>"
(or your self-managed host). - Make sure
GITLAB_TOKEN
is available in the environment where the clone happens (build-time in CI if you build an image, or at runtime in the worker environment). - If you prefer embedding the token in a URL (less secure), you can use:
Copy code
source=f"<https://oauth2:{os.environ['GITLAB_TOKEN']}@gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>"
To confirm what Prefect is trying to clone, enable verbose logs:
Copy code
export PREFECT_LOGGING_LEVEL=DEBUG
export GIT_TRACE=1
export GIT_CURL_VERBOSE=1
This will print the exact remote. You should see a proper https URL once the above changes are in place. Docs: Prefect GitLab integration If you can share the snippet you’re using to construct
Flow.from_source(...)
or the deployment code/CLI you ran, I can point to the exact line to change.
o
@Marvin is i use source=f"https://oauth2:{os.environ['GITLAB_TOKEN']}@gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git" it says Traceback (most recent call last): File "/uvd-workflow-orchestrator-example-prefect/dev/dev_serve_local_code.py", line 34, in <module> flow.from_source( ~~~~~~~~~~~~~~~~^ source=repo, ^^^^^^^^^^^^ entrypoint="workflows/workflow_with_non_and_decorated_task.py:my_flow", ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/home/labor/.local/lib/python3.13/site-packages/prefect/_internal/compatibility/async_dispatch.py", line 94, in wrapper return fn(*args, **kwargs) File "/home/labor/.local/lib/python3.13/site-packages/prefect/flows.py", line 1365, in from_source run_coro_as_sync(storage.pull_code()) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^ File "/home/labor/.local/lib/python3.13/site-packages/prefect/utilities/asyncutils.py", line 207, in run_coro_as_sync return call.result() ~~~~~~~~~~~^^ File "/home/labor/.local/lib/python3.13/site-packages/prefect/_internal/concurrency/calls.py", line 365, in result return self.future.result(timeout=timeout) ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ File "/home/labor/.local/lib/python3.13/site-packages/prefect/_internal/concurrency/calls.py", line 192, in result return self.__get_result() ~~~~~~~~~~~~~~~~~^^ File "/usr/local/lib/python3.13/concurrent/futures/_base.py", line 401, in __get_result raise self._exception File "/home/labor/.local/lib/python3.13/site-packages/prefect/_internal/concurrency/calls.py", line 441, in _run_async result = await coro ^^^^^^^^^^ File "/home/labor/.local/lib/python3.13/site-packages/prefect/utilities/asyncutils.py", line 188, in coroutine_wrapper return await task ^^^^^^^^^^ File "/home/labor/.local/lib/python3.13/site-packages/prefect/runner/storage.py", line 348, in pull_code await self._clone_repo() File "/home/labor/.local/lib/python3.13/site-packages/prefect/runner/storage.py", line 393, in _clone_repo raise RuntimeError( ...<2 lines>... ) from exc_chain RuntimeError: Failed to clone repository with exit code 128.
m
thought for 30.2 seconds
I see the issue: the URL you’re passing is using Slack link formatting. In code, you must use a plain URL string—no angle brackets, no pipe, no “display text.” Correct example with an embedded token:
Copy code
import os
from prefect.flows import Flow

git_url = f"<https://oauth2:{os.environ['GITLAB_TOKEN']}@gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>"

# Optional: sanity check the URL in the same environment
import subprocess
subprocess.run(["git", "ls-remote", git_url], check=True)

flow = Flow.from_source(
    source=git_url,
    entrypoint="workflows/workflow_with_non_and_decorated_task.py:my_flow",
)
A few important notes: - Do not include Slack-style brackets or pipes in code. This is wrong:
"<https://oauth2:${GITLAB_TOKEN}@gitlab.com/...|...>"
- You can safely use classmethod form; prefer
Flow.from_source(...)
over
flow.from_source(...)
to avoid variable shadowing. - In your traceback, you passed
source=repo
but you showed a string URL above—make sure you pass the variable that actually holds the URL, e.g.,
source=git_url
. Recommended approach for private GitLab repos (no token in URL):
Copy code
import os
from prefect.flows import Flow
from prefect_gitlab.repositories import GitLabRepository
from prefect_gitlab.credentials import GitLabCredentials

assert os.getenv("GITLAB_TOKEN"), "GITLAB_TOKEN is not set"

repo = GitLabRepository(
    repository="uvd/uvd-workflow-orchestrator-example-prefect",  # full namespace, no .git
    reference="main",                                            # optional
    host="<http://gitlab.com|gitlab.com>",                                           # or your self-managed host
    credentials=GitLabCredentials(token=os.environ["GITLAB_TOKEN"]),
)

flow = Flow.from_source(
    source=repo,
    entrypoint="workflows/workflow_with_non_and_decorated_task.py:my_flow",
)
If it still fails, turn on debug and confirm the exact remote Prefect is cloning:
Copy code
export PREFECT_LOGGING_LEVEL=DEBUG
export GIT_TRACE=1
export GIT_CURL_VERBOSE=1
You should see a full https URL; if you see
uvd/uvd-workflow-orchestrator-example-prefect
without a host, that’s the problem. Docs for reference: Prefect GitLab integration If you paste your current
Flow.from_source(...)
snippet (exact values minus the token), I’ll pinpoint the fix.
o
@Marvin from the subproess i get == Info: error reading ca cert file Problem with the SSL CA cert (path? access rights?)
m
thought for 122.9 seconds
Got it — that error is coming from Git/cURL, not Prefect: the process that’s doing the clone can’t read a trusted CA bundle. This happens when: - You’re behind a corporate proxy with a custom CA - You’re talking to a self-managed GitLab with an internal CA - An env var points to a non-existent CA file (SSL_CERT_FILE, GIT_SSL_CAINFO, REQUESTS_CA_BUNDLE) Quick triage on the machine/container where the clone happens 1) Check env vars and the paths they point to
Copy code
import os, pathlib
for k in ["SSL_CERT_FILE", "REQUESTS_CA_BUNDLE", "GIT_SSL_CAINFO"]:
    v = os.environ.get(k)
    print(k, "=", v, "exists?", pathlib.Path(v).is_file() if v else None)
If any var points to a missing file, unset it or fix the path. 2) Sanity test from the SAME environment
Copy code
export GIT_TRACE=1
export GIT_CURL_VERBOSE=1
git ls-remote <https://gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>
# If private, use your token:
git ls-remote <https://oauth2:${GITLAB_TOKEN}@gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>
If this fails with the same CA error, it’s an environment cert problem (not Prefect). Fixes depending on where you run A) Local machine - If you have a custom corporate CA, install it into your OS trust store: - Debian/Ubuntu:
Copy code
sudo cp company.crt /usr/local/share/ca-certificates/company.crt
    sudo update-ca-certificates
- Alpine:
Copy code
sudo apk add --no-cache ca-certificates
    sudo cp company.crt /usr/local/share/ca-certificates/company.crt
    sudo update-ca-certificates
- RHEL/CentOS:
Copy code
sudo cp company.crt /etc/pki/ca-trust/source/anchors/
    sudo update-ca-trust
- Or point Git to the bundle explicitly (ensure the file exists):
Copy code
git config --global http.sslCAInfo /etc/ssl/certs/ca-certificates.crt
  # RHEL path often: /etc/pki/tls/certs/ca-bundle.crt
B) Docker image used for deploy or worker - Install certs and add custom CA in your image:
Copy code
# Debian/Ubuntu base
RUN apt-get update && apt-get install -y ca-certificates && update-ca-certificates

# Alpine base
RUN apk add --no-cache ca-certificates && update-ca-certificates

# Add your custom CA if needed
COPY company.crt /usr/local/share/ca-certificates/company.crt
RUN update-ca-certificates
- If you must point Git at a non-default bundle, set env vars:
Copy code
ENV GIT_SSL_CAINFO=/etc/ssl/certs/ca-certificates.crt
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
C) Kubernetes worker - Mount your CA as a Secret/ConfigMap into the pod and set env vars to that path. - In Prefect 3, you can inject env via job variables on the deployment:
Copy code
flow.deploy(
  name="etl-prod",
  work_pool_name="k8s-pool",
  job_variables={
    "env": {
      "GIT_SSL_CAINFO": "/etc/ssl/certs/ca-certificates.crt",
      "SSL_CERT_FILE": "/etc/ssl/certs/ca-certificates.crt",
    }
  },
)
Then ensure that path exists in the pod (either from base image certs or your mounted CA). Temporary test only (not for production)
Copy code
export GIT_SSL_NO_VERIFY=true
git ls-remote <https://gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>
If this makes it work, it confirms the problem is CA trust. Re-enable verification after you fix the CA bundle. Once the CA is fixed, use a clean URL in your code (no Slack formatting):
Copy code
from prefect.flows import Flow
import os

git_url = f"<https://oauth2:{os.environ['GITLAB_TOKEN']}@gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>"

flow = Flow.from_source(
    source=git_url,  # or use GitLabRepository with token
    entrypoint="workflows/workflow_with_non_and_decorated_task.py:my_flow",
)
Docs to help with deployment env and GitLab integration: - Prefect GitLab integration: docs - Customize job variables/env on deployments: docs Can you share: - Are you on gitlab.com or self-managed GitLab?
- Are you running locally, in Docker, or on a K8s worker? - Do you have a corporate/custom CA you need to trust? I can give exact commands/config for your environment.
o
@ The existing repository at /tmp/runner_storage/1e0894bf-93cf-4796-b2a4-158996457b05/uvd-workflow-orchestrator-example-prefect does not match the configured repository
@Marvin The existing repository at /tmp/runner_storage/1e0894bf-93cf-4796-b2a4-158996457b05/uvd-workflow-orchestrator-example-prefect does not match the configured repository
m
thought for 110.8 seconds
That message means Prefect found a cached clone at that path, but its “origin” URL doesn’t match the repo you’ve now configured. This often happens after you fix/change the source (e.g., from
uvd/...
to a full `https://gitlab.com/...`), or after switching from unauthenticated to token-authenticated URLs. What to do now 1) Inspect the cached repo’s origin to see what Prefect cloned earlier
Copy code
git -C /tmp/runner_storage/1e0894bf-93cf-4796-b2a4-158996457b05/uvd-workflow-orchestrator-example-prefect remote -v
You’ll likely see an origin like
uvd/uvd-workflow-orchestrator-example-prefect
(missing host) which doesn’t match your corrected
<https://gitlab.com/>...
URL. 2) Remove the cached storage directory, then retry
Copy code
rm -rf /tmp/runner_storage/1e0894bf-93cf-4796-b2a4-158996457b05
Then re-run your deployment/serve. If you’re running in a container/worker, make sure that path isn’t persisted across runs. 3) Use a stable, fully qualified source going forward - Recommended for private repos: use the GitLab integration so the remote URL stays stable and the token isn’t embedded in the URL.
Copy code
import os
from prefect.flows import Flow
from prefect_gitlab.repositories import GitLabRepository
from prefect_gitlab.credentials import GitLabCredentials

repo = GitLabRepository(
    repository="uvd/uvd-workflow-orchestrator-example-prefect",  # full namespace, no .git
    reference="main",                                            # optional
    host="<http://gitlab.com|gitlab.com>",
    credentials=GitLabCredentials(token=os.environ["GITLAB_TOKEN"]),
)

flow = Flow.from_source(
    source=repo,
    entrypoint="workflows/workflow_with_non_and_decorated_task.py:my_flow",
)
- If you must embed the token in the URL (ensure no Slack formatting):
Copy code
import os
from prefect.flows import Flow

git_url = f"<https://oauth2:{os.environ['GITLAB_TOKEN']}@gitlab.com/uvd/uvd-workflow-orchestrator-example-prefect.git>"

flow = Flow.from_source(
    source=git_url,
    entrypoint="workflows/workflow_with_non_and_decorated_task.py:my_flow",
)
Notes - If the token value changes and you embed it in the origin URL, Prefect may see that as a “different repository.” Prefer the
GitLabRepository(..., credentials=...)
approach to keep the origin stable. - Ensure the token is present in the environment where the clone happens (CI during build, or the worker at runtime). - If you’re on a self-managed GitLab with a custom CA, make sure the container/host trusts that CA (the earlier SSL CA error points to that). If you share how you’re running (local, Docker worker, K8s) and your current
Flow.from_source(...)
snippet, I can suggest the exact cleanup + configuration to make this stick.