Skip to content
Latchkey

Tavern "ConnectionError: Max retries exceeded" in CI

Tavern uses requests under the hood, so an unreachable API surfaces as "ConnectionError: Max retries exceeded" with a "Connection refused". The service was not listening when the stage fired.

What this error means

A Tavern stage fails with "requests.exceptions.ConnectionError: HTTPConnectionPool(...): Max retries exceeded ... Connection refused" before any assertion runs.

tavern
E   requests.exceptions.ConnectionError:
E   HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url:
E   /users/1 (Caused by NewConnectionError('Connection refused'))

Common causes

The API is not up when Tavern runs

pytest started the Tavern stages before the service was listening, so requests could not connect.

The base URL is wrong for the CI network

The URL points at localhost when the API runs in a service container reachable by a different hostname, so the connection is refused.

How to fix it

Wait for readiness before pytest

  1. Start the API and poll its health endpoint until it responds.
  2. Only then run the Tavern pytest suite.
  3. Point BASE_URL at the reachable host for the CI network.
.github/workflows/ci.yml
- run: |
    for i in $(seq 1 30); do curl -sf http://localhost:8000/health && break; sleep 2; done
- run: BASE_URL=http://localhost:8000 pytest tests/tavern/

Add a retry stage to absorb warm-up

Tavern can retry a stage with max_retries so an initially slow endpoint does not fail immediately.

test_health.tavern.yaml
stages:
  - name: Wait for API
    max_retries: 5
    request:
      url: "{tavern.env_vars.BASE_URL}/health"
    response:
      status_code: 200

How to prevent it

  • Gate the Tavern suite on a readiness check.
  • Set BASE_URL to a host reachable from the CI job.
  • Use a retrying health stage to absorb startup latency.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →