<@ULVA73B9P> must i manually configure work pools ...
# ask-marvin
o
@Marvin must i manually configure work pools or can i do that with start command of docker or in compose script
m
thought for 187.4 seconds
Short answer: you don’t have to pre-create work pools. In Prefect 3.x, a worker can auto-create the work pool when it starts. That means you can do it with a
docker run
command or inside a docker-compose file. For production, many teams still prefer to explicitly create/update the pool first so they can control settings like the base job template. Options: - Let the worker auto-create the pool (simple) - If the pool doesn’t exist, pass the worker type so Prefect knows what to create. - Example with Docker worker:
Copy code
docker run --rm \
    -e PREFECT_API_URL=<your-api-url> \
    -e PREFECT_API_KEY=<your-api-key-if-using-cloud> \
    -v /var/run/docker.sock:/var/run/docker.sock \
    prefecthq/prefect:latest \
    prefect worker start --pool my-docker-pool --type docker
Notes: -
--type docker
is needed if the pool doesn’t exist yet. - If the pool already exists, Prefect will infer the type from the pool and
--type
isn’t required. - Create/update the pool before starting the worker (recommended for controlled config) - Idempotent compose pattern:
Copy code
services:
    pool-init:
      image: prefecthq/prefect:latest
      environment:
        PREFECT_API_URL: <your-api-url>
        PREFECT_API_KEY: <your-api-key-if-using-cloud>
      command: >
        sh -c "
          prefect work-pool create my-docker-pool --type docker --overwrite || true
        "

    docker-worker:
      image: prefecthq/prefect:latest
      depends_on:
        - pool-init
      environment:
        PREFECT_API_URL: <your-api-url>
        PREFECT_API_KEY: <your-api-key-if-using-cloud>
      volumes:
        - /var/run/docker.sock:/var/run/docker.sock
      command: prefect worker start --pool my-docker-pool
      restart: unless-stopped
- Use
--base-job-template
on
work-pool create
if you need a custom job template:
Copy code
prefect work-pool create my-docker-pool --type docker --base-job-template ./base-job-template.json --overwrite
Docs for reference: - Work pools concept: Work pools - Managing work pools: Manage work pools - Docker worker guide: Docker worker - CLI reference: work-pool and worker Quick check: - Using Prefect Cloud? Set
PREFECT_API_KEY
and point
PREFECT_API_URL
to your workspace URL, or run
prefect cloud login
in your container entrypoint. - Self-hosted Prefect Server? Set
PREFECT_API_URL
to your server’s API (e.g., `http://prefect-server:4200/api`). If you share whether you’re on Cloud or self-hosted and which worker type you want (docker/kubernetes/process), I can tailor the exact compose snippet for your setup.
o
@Marvin prefect-worker-docker-process-1 | Traceback (most recent call last): prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 101, in map_httpcore_exceptions prefect-worker-docker-process-1 | yield prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 394, in handle_async_request prefect-worker-docker-process-1 | resp = await self._pool.handle_async_request(req) prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 256, in handle_async_request prefect-worker-docker-process-1 | raise exc from None prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 236, in handle_async_request prefect-worker-docker-process-1 | response = await connection.handle_async_request( prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | pool_request.request prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | ) prefect-worker-docker-process-1 | ^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 101, in handle_async_request prefect-worker-docker-process-1 | raise exc prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 78, in handle_async_request prefect-worker-docker-process-1 | stream = await self._connect(request) prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 124, in _connect prefect-worker-docker-process-1 | stream = await self._network_backend.connect_tcp(**kwargs) prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_backends/auto.py", line 31, in connect_tcp prefect-worker-docker-process-1 | return await self._backend.connect_tcp( prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | ...<5 lines>... prefect-worker-docker-process-1 | ) prefect-worker-docker-process-1 | ^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_backends/anyio.py", line 113, in connect_tcp prefect-worker-docker-process-1 | with map_exceptions(exc_map): prefect-worker-docker-process-1 | ~~~~~~~~~~~~~~^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/contextlib.py", line 162, in exit prefect-worker-docker-process-1 | self.gen.throw(value) prefect-worker-docker-process-1 | ~~~~~~~~~~~~~~^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions prefect-worker-docker-process-1 | raise to_exc(exc) from exc prefect-worker-docker-process-1 | httpcore.ConnectError: All connection attempts failed prefect-worker-docker-process-1 | prefect-worker-docker-process-1 | The above exception was the direct cause of the following exception: prefect-worker-docker-process-1 | prefect-worker-docker-process-1 | Traceback (most recent call last): prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/_utilities.py", line 44, in wrapper prefect-worker-docker-process-1 | return fn(*args, **kwargs) prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/_types.py", line 159, in sync_fn prefect-worker-docker-process-1 | return asyncio.run(async_fn(*args, **kwargs)) prefect-worker-docker-process-1 | ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/asyncio/runners.py", line 195, in run prefect-worker-docker-process-1 | return runner.run(main) prefect-worker-docker-process-1 | ~~~~~~~~~~^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/asyncio/runners.py", line 118, in run prefect-worker-docker-process-1 | return self._loop.run_until_complete(task) prefect-worker-docker-process-1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/asyncio/base_events.py", line 725, in run_until_complete prefect-worker-docker-process-1 | return future.result() prefect-worker-docker-process-1 | ~~~~~~~~~~~~~^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/worker.py", line 115, in start prefect-worker-docker-process-1 | is_paused = await _check_work_pool_paused(work_pool_name) prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/worker.py", line 180, in _check_work_pool_paused prefect-worker-docker-process-1 | work_pool = await client.read_work_pool(work_pool_name=work_pool_name) prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/client/orchestration/_work_pools/client.py", line 419, in read_work_pool prefect-worker-docker-process-1 | response = await self.request( prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | ...<3 lines>... prefect-worker-docker-process-1 | ) prefect-worker-docker-process-1 | ^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/client/orchestration/base.py", line 53, in request prefect-worker-docker-process-1 | return await self._client.send(request) prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/client/base.py", line 348, in send prefect-worker-docker-process-1 | response = await self._send_with_retry( prefect-worker-docker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-docker-process-1 | ...<24 lines>...
m
thought for 173.9 seconds
Thanks for the stack trace — that error means the worker cannot reach the Prefect API. In other words,
prefect worker start
is trying to read the work pool, but all TCP connection attempts to
PREFECT_API_URL
are failing. Common causes and quick fixes: - Missing or wrong
PREFECT_API_URL
- Using
<http://localhost:4200/api>
from inside a container (localhost points to the container, not your host) - Prefect Server not started yet (ordering/healthcheck issue in compose) - Using Prefect Cloud but missing
PREFECT_API_KEY
, wrong URL, or proxy blocking egress Diagnose inside the worker container:
Copy code
prefect config view --show-sources
Confirm: -
api.url
is set to the correct endpoint - If using Cloud,
api.key
is set and valid If you’re using Prefect Server with docker-compose: - Point the worker at the server service name, not localhost - Example compose snippet:
Copy code
services:
  prefect-server:
    image: prefecthq/prefect:latest
    command: prefect server start
    ports:
      - "4200:4200"

  prefect-worker:
    image: prefecthq/prefect:latest
    depends_on:
      - prefect-server
    environment:
      PREFECT_API_URL: <http://prefect-server:4200/api>
    # For Docker work pool only; not needed for process worker
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: prefect worker start --pool my-docker-pool --type docker
    restart: unless-stopped
If your server is running on your host (not in compose): - Use host.docker.internal from the container:
Copy code
PREFECT_API_URL=<http://host.docker.internal:4200/api>
- On Linux, add this to the worker service:
Copy code
extra_hosts:
  - "host.docker.internal:host-gateway"
If you’re using Prefect Cloud: - Set both URL and API key:
Copy code
PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>"
PREFECT_API_KEY="pnb_xxx or pnu_xxx"
- Test from the container:
Copy code
curl -I "$PREFECT_API_URL/health"
If the pool might not exist yet, include the worker type on first start so it can auto-create the pool:
Copy code
prefect worker start --pool my-docker-pool --type docker
# or for a process worker
prefect worker start --pool my-process-pool --type process
Helpful docs: - Settings & profiles: Settings and profiles - Connect to Cloud: Connect to Cloud - Docker worker guide: Docker worker - Self-hosted via docker-compose: Docker Compose for Server - Cloud troubleshooting: Troubleshoot Cloud If you can share: - Whether you’re on Cloud or self-hosted - Your
PREFECT_API_URL
value - Your docker-compose snippet for the worker (and server, if applicable) …I can pinpoint the exact fix for your setup.
o
@Marvin but i use environment: PREFECT_API_URL: http://prefect-server:4200/api already in the worker pools
m
thought for 59.2 seconds
Got it — if you already set
PREFECT_API_URL=<http://prefect-server:4200/api>
but still see “All connection attempts failed”, it means the worker container cannot reach the server at that hostname/port. Most common causes and quick fixes: 1) The server isn’t reachable on the container network - Ensure the server and worker are in the same docker-compose project/network and the service is named
prefect-server
. - If the server runs in a different compose project or separately, put both on a shared network or switch the URL to the host: - If server runs on your host: use
<http://host.docker.internal:4200/api>
(on Linux add
extra_hosts: ["host.docker.internal:host-gateway"]
). - If in a different compose project: use a user-defined external network and attach both services to it. 2) The server is binding to 127.0.0.1 inside its container - Make sure the server binds to 0.0.0.0 so other containers can connect:
Copy code
command: prefect server start --host 0.0.0.0 --port 4200
3) The worker starts before the server is ready - Add a healthcheck and depend on it:
Copy code
prefect-server:
  image: prefecthq/prefect:latest
  command: prefect server start --host 0.0.0.0 --port 4200
  ports:
    - "4200:4200"
  healthcheck:
    test: ["CMD", "curl", "-f", "<http://localhost:4200/api/health>"]
    interval: 5s
    timeout: 3s
    retries: 20

prefect-worker:
  image: prefecthq/prefect:latest
  depends_on:
    prefect-server:
      condition: service_healthy
  environment:
    PREFECT_API_URL: <http://prefect-server:4200/api>
  command: prefect worker start --pool my-pool --type process
  restart: unless-stopped
4) DNS/hostname mismatch - From inside the worker container, test resolution and connectivity:
Copy code
prefect config view --show-sources
getent hosts prefect-server
curl -v <http://prefect-server:4200/api/health>
- If
getent
can’t resolve
prefect-server
, the services are not on the same network or the name differs. 5) You’re on Prefect Cloud by mistake - If
PREFECT_API_KEY
is set and
PREFECT_API_URL
points to Prefect Cloud, the worker will try Cloud. For self-hosted, unset
PREFECT_API_KEY
or ensure
PREFECT_API_URL
truly points to your server (and server is reachable). Helpful references: - Docker Compose for self-hosted server: Docker Compose guide - Server overview: Server - Settings & profiles (API URL / key): Settings and profiles If you can share your docker-compose snippet (server + worker services), I’ll point out the exact change to make.
o
@Marvin this is the info at startup prefect-server-1 | prefect-server-1 | _ _ _ _ _ _ _____ prefect-server-1 | | _ \ _ \ __| __| __/ _| _| prefect-server-1 | | _/ / _|| _|| | (_ | | prefect-server-1 | |_| |_|_\___|_| |___\___| |_| prefect-server-1 | prefect-server-1 | Configure Prefect to communicate with the server with: prefect-server-1 | prefect-server-1 | prefect config set PREFECT_API_URL=http://0.0.0.0:4200/api prefect-server-1 | prefect-server-1 | View the API reference documentation at http://0.0.0.0:4200/docs prefect-server-1 | prefect-server-1 | Check out the dashboard at http://0.0.0.0:4200
m
thought for 29.5 seconds
Thanks for sharing that log. Important nuance: the server prints 0.0.0.0 because that’s the bind address. Clients (like your worker) should not use 0.0.0.0 to connect. From another container, you must use a routable host: - If server and worker are in the same docker-compose project/network: use the server’s service name (e.g., `http://prefect-server:4200/api`). - If they are in different compose projects (your container names suggest that:
prefect-server-1
vs
prefect-worker-docker-process-1
), the worker won’t resolve
prefect-server
. Either: - Put both services in the same compose file/project, or - Attach both to a shared user-defined network, or - Point the worker at the host’s published port via
host.docker.internal
. Concrete fixes: Option A — same compose project/network - Ensure both services are defined in one compose file (or started with the same
-p <project>
). - Use the service name:
Copy code
environment:
  PREFECT_API_URL: <http://prefect-server:4200/api>
Option B — shared external network
Copy code
networks:
  prefect-net:
    name: prefect-net
    external: true

services:
  prefect-server:
    networks: [prefect-net]
    command: prefect server start --host 0.0.0.0 --port 4200

  prefect-worker:
    networks: [prefect-net]
    environment:
      PREFECT_API_URL: <http://prefect-server:4200/api>
Create the network once:
Copy code
docker network create prefect-net
Option C — connect via host port - If the server is reachable on your host at 4200:
Copy code
environment:
  PREFECT_API_URL: <http://host.docker.internal:4200/api>
- On Linux add:
Copy code
extra_hosts:
  - "host.docker.internal:host-gateway"
Add readiness/health checks to avoid race conditions:
Copy code
prefect-server:
  command: prefect server start --host 0.0.0.0 --port 4200
  healthcheck:
    test: ["CMD", "curl", "-f", "<http://localhost:4200/api/health>"]
    interval: 5s
    timeout: 3s
    retries: 20

prefect-worker:
  depends_on:
    prefect-server:
      condition: service_healthy
Validate from inside the worker container:
Copy code
prefect config view --show-sources
getent hosts prefect-server
curl -v <http://prefect-server:4200/api/health>
Key points: - Don’t set
PREFECT_API_URL
to
<http://0.0.0.0:4200/api>
in the worker. - Make sure DNS for
prefect-server
resolves inside the worker (same network or use host.docker.internal). Docs: - Self-hosted with docker-compose: Docker Compose guide - Server overview: Server - Settings & profiles: Settings and profiles If you paste your compose snippet (server + worker sections), I’ll mark the exact changes to make.
o
@Marvin how can i set the dns name in the docker network of the prefect server explicitly in docker compose?
m
thought for 38.1 seconds
You can control the DNS name other containers use by giving the Prefect Server service a network alias (or by putting both services on the same user-defined network and using the service name). The alias becomes the resolvable hostname on that network. Recommended pattern with a shared user-defined network and aliases:
Copy code
# Create the network once (shared across compose projects)
# docker network create prefect-net

networks:
  prefect-net:
    external: true

services:
  prefect-server:
    image: prefecthq/prefect:latest
    command: prefect server start --host 0.0.0.0 --port 4200
    networks:
      prefect-net:
        aliases:
          - prefect-api   # <-- explicit DNS name for the server
    ports:
      - "4200:4200"

  prefect-worker:
    image: prefecthq/prefect:latest
    depends_on:
      - prefect-server
    networks:
      - prefect-net
    environment:
      PREFECT_API_URL: <http://prefect-api:4200/api>  # <-- use the alias here
    command: prefect worker start --pool my-pool --type process
    restart: unless-stopped
Notes: - The service name (e.g.,
prefect-server
) is also a DNS name on the network. Use
aliases
if you want a different or additional stable name like
prefect-api
. - If your server and worker are in different compose files/projects, they must share the same external network (as shown) to resolve each other by name. - Avoid
container_name
unless you really need it; it limits scaling and can collide. Prefer
networks.<name>.aliases
. - Setting
hostname
only affects the container’s internal hostname; it doesn’t create a name other containers can resolve. Use
aliases
for that. If your server runs on the host instead of a container, map a DNS name to the host gateway from the worker:
Copy code
services:
  prefect-worker:
    extra_hosts:
      - "prefect-api:host-gateway"
    environment:
      PREFECT_API_URL: <http://prefect-api:4200/api>
Quick validation from the worker container:
Copy code
getent hosts prefect-api
curl -v <http://prefect-api:4200/api/health>
If you paste your current compose snippets (server + worker), I can suggest the exact edits.
o
@Marvin how can i get all dns names of services in one dockernetwork?
m
thought for 49.8 seconds
Short answer: there isn’t a single “list all DNS records” command, but you can derive them from the containers attached to the network and their per-network aliases. Two handy ways: 1) List containers and IPs on a network
Copy code
docker network inspect <network> -f '{{range $id, $c := .Containers}}{{printf "%s\t%s\n" $c.Name $c.IPv4Address}}{{end}}'
2) List all resolvable names (service name, container name, and any custom aliases) per container on that network
Copy code
NET=<network>
for id in $(docker network inspect "$NET" -f '{{range $id, $c := .Containers}}{{println $id}}{{end}}'); do
  docker inspect "$id" \
    --format "{{.Name}}: {{(index .NetworkSettings.Networks \"$NET\").Aliases}}"
done
Notes: - Docker’s embedded DNS registers, per network, the container name, the Compose service name, and any
networks.<net>.aliases
you set. - These names only resolve between containers that share that network. - To test a specific name from a container on that network:
Copy code
getent hosts <name>
curl -v http://<name>:<port>/api/health
If you share your network name, I can help tailor the exact command for your setup.
o
@Marvin from browser http://localhost:4200/api/health true from prefect-worker http://prefect-server:4200/api/health true but still prefect-worker-process-1 | Traceback (most recent call last): prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 101, in map_httpcore_exceptions prefect-worker-process-1 | yield prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 394, in handle_async_request prefect-worker-process-1 | resp = await self._pool.handle_async_request(req) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 256, in handle_async_request prefect-worker-process-1 | raise exc from None prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 236, in handle_async_request prefect-worker-process-1 | response = await connection.handle_async_request( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | pool_request.request prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 101, in handle_async_request prefect-worker-process-1 | raise exc prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 78, in handle_async_request prefect-worker-process-1 | stream = await self._connect(request) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 124, in _connect prefect-worker-process-1 | stream = await self._network_backend.connect_tcp(**kwargs) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_backends/auto.py", line 31, in connect_tcp prefect-worker-process-1 | return await self._backend.connect_tcp( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ...<5 lines>... prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_backends/anyio.py", line 113, in connect_tcp prefect-worker-process-1 | with map_exceptions(exc_map): prefect-worker-process-1 | ~~~~~~~~~~~~~~^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/contextlib.py", line 162, in exit prefect-worker-process-1 | self.gen.throw(value) prefect-worker-process-1 | ~~~~~~~~~~~~~~^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions prefect-worker-process-1 | raise to_exc(exc) from exc prefect-worker-process-1 | httpcore.ConnectError: All connection attempts failed prefect-worker-process-1 | prefect-worker-process-1 | The above exception was the direct cause of the following exception: prefect-worker-process-1 | prefect-worker-process-1 | Traceback (most recent call last): prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/_utilities.py", line 44, in wrapper prefect-worker-process-1 | return fn(*args, **kwargs) prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/_types.py", line 159, in sync_fn prefect-worker-process-1 | return asyncio.run(async_fn(*args, **kwargs)) prefect-worker-process-1 | ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/asyncio/runners.py", line 195, in run prefect-worker-process-1 | return runner.run(main) prefect-worker-process-1 | ~~~~~~~~~~^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/asyncio/runners.py", line 118, in run prefect-worker-process-1 | return self._loop.run_until_complete(task) prefect-worker-process-1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/asyncio/base_events.py", line 725, in run_until_complete prefect-worker-process-1 | return future.result() prefect-worker-process-1 | ~~~~~~~~~~~~~^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/worker.py", line 115, in start prefect-worker-process-1 | is_paused = await _check_work_pool_paused(work_pool_name) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/worker.py", line 180, in _check_work_pool_paused prefect-worker-process-1 | work_pool = await client.read_work_pool(work_pool_name=work_pool_name) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/client/orchestration/_work_pools/client.py", line 419, in read_work_pool prefect-worker-process-1 | response = await self.request( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ...<3 lines>... prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/client/orchestration/base.py", line 53, in request prefect-worker-process-1 | return await self._client.send(request) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/client/base.py", line 348, in send prefect-worker-process-1 | response = await self._send_with_retry( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ...<24 lines>... prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/client/base.py", line 268, in _send_with_retry prefect-worker-process-1 | response = await send(request, *send_args, **send_kwargs) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_client.py", line 1629, in send prefect-worker-process-1 | response = await self._send_handling_auth( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ...<4 lines>... prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_client.py", line 1657, in _send_handling_auth prefect-worker-process-1 | response = await self._send_handling_redirects( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ...<3 lines>... prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_client.py", line 1694, in _send_handling_redirects prefect-worker-process-1 | response = await self._send_single_request(request) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_client.py", line 1730, in _send_single_request prefect-worker-process-1 | response = await transport.handle_async_request(request) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 393, in handle_async_request prefect-worker-process-1 | with map_httpcore_exceptions(): prefect-worker-process-1 | ~~~~~~~~~~~~~~~~~~~~~~~^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/contextlib.py", line 162, in exit prefect-worker-process-1 | self.gen.throw(value) prefect-worker-process-1 | ~~~~~~~~~~~~~~^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 118, in map_httpcore_exceptions prefect-worker-process-1 | raise mapped_exc(message) from exc prefect-worker-process-1 | httpx.ConnectError: All connection attempts failed
m
Your message was too long, here's your message at the allowed limit: from browser <http //localhost 4200/api/health> true from prefect-worker <http //prefect-server 4200/api/health> true but still prefect-worker-process-1 | Traceback (most recent call last) prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpx/_transports/default py line 101 in map_httpcore_exceptions prefect-worker-process-1 | yield prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpx/_transports/default py line 394 in handle_async_request prefect-worker-process-1 | resp = await self _pool handle_async_request(req) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_async/connection_pool py line 256 in handle_async_request prefect-worker-process-1 | raise exc from None prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_async/connection_pool py line 236 in handle_async_request prefect-worker-process-1 | response = await connection handle_async_request( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | pool_request request prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_async/connection py line 101 in handle_async_request prefect-worker-process-1 | raise exc prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_async/connection py line 78 in handle_async_request prefect-worker-process-1 | stream = await self _connect(request) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_async/connection py line 124 in _connect prefect-worker-process-1 | stream = await self _network_backend connect_tcp(*kwargs) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_backends/auto py line 31 in connect_tcp prefect-worker-process-1 | return await self _backend connect_tcp( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | <5 lines> prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_backends/anyio py line 113 in connect_tcp prefect-worker-process-1 | with map_exceptions(exc_map) prefect-worker-process-1 | ~~~~~~~~~~~~~~^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/contextlib py line 162 in exit prefect-worker-process-1 | self gen throw(value) prefect-worker-process-1 | ~~~~~~~~~~~~~~^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/httpcore/_exceptions py line 14 in map_exceptions prefect-worker-process-1 | raise to_exc(exc) from exc prefect-worker-process-1 | httpcore ConnectError All connection attempts failed prefect-worker-process-1 | prefect-worker-process-1 | The above exception was the direct cause of the following exception prefect-worker-process-1 | prefect-worker-process-1 | Traceback (most recent call last) prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/cli/_utilities py line 44 in wrapper prefect-worker-process-1 | return fn(*args *kwargs) prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/cli/_types py line 159 in sync_fn prefect-worker-process-1 | return asyncio run(async_fn(*args *kwargs)) prefect-worker-process-1 | ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/asyncio/runners py line 195 in run prefect-worker-process-1 | return runner run(main) prefect-worker-process-1 | ~~~~~~~~~~^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/asyncio/runners py line 118 in run prefect-worker-p
rocess-1 | return self _loop run_until_complete(task) prefect-worker-process-1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/asyncio/base_events py line 725 in run_until_complete prefect-worker-process-1 | return future result() prefect-worker-process-1 | ~~~~~~~~~~~~~^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/cli/worker py line 115 in start prefect-worker-process-1 | is_paused = await _check_work_pool_paused(work_pool_name) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/cli/worker py line 180 in _check_work_pool_paused prefect-worker-process-1 | work_pool = await client read_work_pool(work_pool_name=work_pool_name) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/client/orchestration/_work_pools/client py line 419 in read_work_pool prefect-worker-process-1 | response = await self request( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | <3 lines> prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/client/orchestration/base py line 53 in request prefect-worker-process-1 | return await self _client send(request) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/client/base py line 348 in send prefect-worker-process-1 | response = await self _send_with_retry( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | <24 lines> prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File /usr/local/lib/python3 13/site-packages/prefect/client/base py line 268 in _send_with_retry prefect-worker-process-1 | response = await send(request *send_args *send_kwargs) prefect-worker-process-1 |
o
@Marvin from browser http://localhost:4200/api/health true from prefect-worker http://prefect-server:4200/api/health true but still prefect-worker-process-1 | Traceback (most recent call last): prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 101, in map_httpcore_exceptions prefect-worker-process-1 | yield prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpx/_transports/default.py", line 394, in handle_async_request prefect-worker-process-1 | resp = await self._pool.handle_async_request(req) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 256, in handle_async_request prefect-worker-process-1 | raise exc from None prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection_pool.py", line 236, in handle_async_request prefect-worker-process-1 | response = await connection.handle_async_request( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | pool_request.request prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 101, in handle_async_request prefect-worker-process-1 | raise exc prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 78, in handle_async_request prefect-worker-process-1 | stream = await self._connect(request) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_async/connection.py", line 124, in _connect prefect-worker-process-1 | stream = await self._network_backend.connect_tcp(**kwargs) prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_backends/auto.py", line 31, in connect_tcp prefect-worker-process-1 | return await self._backend.connect_tcp( prefect-worker-process-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | ...<5 lines>... prefect-worker-process-1 | ) prefect-worker-process-1 | ^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_backends/anyio.py", line 113, in connect_tcp prefect-worker-process-1 | with map_exceptions(exc_map): prefect-worker-process-1 | ~~~~~~~~~~~~~~^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/contextlib.py", line 162, in exit prefect-worker-process-1 | self.gen.throw(value) prefect-worker-process-1 | ~~~~~~~~~~~~~~^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions prefect-worker-process-1 | raise to_exc(exc) from exc prefect-worker-process-1 | httpcore.ConnectError: All connection attempts failed prefect-worker-process-1 | prefect-worker-process-1 | The above exception was the direct cause of the following exception: prefect-worker-process-1 | prefect-worker-process-1 | Traceback (most recent call last): prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/_utilities.py", line 44, in wrapper prefect-worker-process-1 | return fn(*args, **kwargs) prefect-worker-process-1 | File "/usr/local/lib/python3.13/site-packages/prefect/cli/_types.py", line 159, in sync_fn prefect-worker-process-1 | return asyncio.run(async_fn(*args, **kwargs)) prefect-worker-process-1 | ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ prefect-worker-process-1 | File "/usr/local/lib/python3.13/asyncio/runners.py", line 195, in run prefect-worker-process-1 | return runner.run(main) prefect-worker-process-1 | ~~~~~~~~~~^^^^^^
m
thought for 58.6 seconds
Great data point — if curl to http://prefect-server:4200/api/health returns true from inside the worker container, the network path is good. The httpcore.ConnectError during worker start almost always means Prefect is using a different API URL than the one you just tested. Most common gotcha I’m seeing in your messages: angle brackets sneaking into the value. Compose should NOT include < and > around the URL. For example, this is wrong:
Copy code
environment:
  PREFECT_API_URL: <http://prefect-server:4200/api>
It must be:
Copy code
environment:
  PREFECT_API_URL: <http://prefect-server:4200/api>
If the brackets are present, Prefect’s client will try to connect to a malformed host and you’ll get ConnectError even though curl with the clean URL works. Let’s verify exactly what Prefect sees inside the worker container: - Print the env var and Prefect’s resolved config
Copy code
echo "$PREFECT_API_URL"
prefect config view --show-sources | grep -i -A1 "api.url"
- Double-check what the Prefect client is actually using
Copy code
python - <<'PY'
import asyncio, os
from prefect.client.orchestration import get_client
async def main():
    print("ENV PREFECT_API_URL =", os.getenv("PREFECT_API_URL"))
    async with get_client() as c:
        print("Client base url   =", str(c._client.base_url))
        r = await c._client.get("/health")
        print("Health JSON       =", r.json())
asyncio.run(main())
PY
If the values don’t exactly match http://prefect-server:4200/api: - Remove any angle brackets - Ensure there’s no trailing whitespace or hidden characters - Make sure no profile in the image is overriding it (env vars should win, but let’s confirm with the show-sources output) Other quick checks: - Ensure the server binds to all interfaces so other containers can reach it:
Copy code
command: prefect server start --host 0.0.0.0 --port 4200
- If the pool might not exist yet, let the worker create it by specifying the type once:
Copy code
prefect worker start --pool my-process-pool --type process
If you paste your worker service from docker-compose (exact environment block and command), I’ll mark the one-line fix.
o
@Marvin what kind of angle brackets are you talking about?
m
thought for 21.5 seconds
I mean the literal ASCII characters “<” and “>”. Slack often wraps URLs like this:
<http://prefect-server:4200/api>
for link formatting. If those angle brackets make it into your docker-compose or env file, Prefect will try to use the URL with the brackets included, which is invalid and causes the ConnectError you’re seeing. Wrong (has angle brackets):
Copy code
environment:
  PREFECT_API_URL: <http://prefect-server:4200/api>
Right (no angle brackets; quoting is optional but safe):
Copy code
environment:
  PREFECT_API_URL: "<http://prefect-server:4200/api>"
Quick checks inside the worker container:
Copy code
echo "$PREFECT_API_URL"
prefect config view --show-sources | grep -i -A1 "api.url"
If you want, paste the exact environment block from your compose file and I’ll confirm it’s clean. If the brackets weren’t the issue, share the
prefect config view --show-sources
output for
api.url
and we’ll keep digging.