Skip to content

Troubleshooting

"connection refused" hitting localhost:8080 right after docker compose up

Expected during the first ~15-30 seconds — server waits for postgres's healthcheck (depends_on: condition: service_healthy) before it even starts, and then runs alembic upgrade head before uvicorn binds the port.

docker compose ps            # postgres should show "healthy"; server "Up"
docker compose logs -f server  # watch for "Running database migrations..." then "Uvicorn running on..."

If it's still refusing connections after a minute, check docker compose logs server for a migration failure (see below) rather than assuming it's still starting.

alembic upgrade head fails at boot

Server logs will show the alembic traceback before the container exits. Common causes:

  • Database not reachableRAI_DATABASE_URL doesn't match the postgres service's actual credentials/host. If you changed POSTGRES_PASSWORD in an override file, RAI_DATABASE_URL must match.
  • Partial/corrupted schema from a previous failed migration — inspect alembic_version table:
    docker compose exec postgres psql -U rai -d rai -c "SELECT * FROM alembic_version;"
    
    Compare against packages/raise-server/alembic/versions/ head. Resolving a stuck migration is case-by-case (out of scope for a generic SOP) — the safe fallback is restoring from a known-good backup (backup-restore.md) rather than hand-editing the version table.

Port already in use (8080 or 5432)

Something else on the host is bound to that port.

# Linux/macOS
lsof -i :8080
lsof -i :5432

Either stop the conflicting process, or remap the host side in a docker-compose.override.yml (leave the container-side port alone):

services:
  server:
    ports:
      - "9080:8080"

GET /health returns "database": "disconnected"

The server process is up but can't reach PostgreSQL — check:

docker compose ps postgres         # is it running and healthy?
docker compose logs postgres       # any crash-loop or OOM in its logs?
docker compose exec postgres pg_isready -U rai -d rai

If postgres itself is healthy but the server still reports disconnected, verify RAI_DATABASE_URL in the server service's environment matches the postgres service's actual POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB — a mismatch here is the most common cause after a manual override.

Export endpoints return 401

/api/v2/export/* require a valid API key resolving to an authenticated member (same as GET /api/v2/metrics) — this is not specific to self-hosted, see export-api-usage.md. Check the Authorization: Bearer <key> header is present and the key hasn't been revoked (docker compose exec postgres psql -U rai -d rai -c "SELECT key_prefix, is_active FROM api_keys;").

Export endpoint returns 400 with "malformed cursor"

The ?cursor= value was hand-edited, truncated, or copied from a different endpoint's response. Cursors are opaque tokens — never construct or edit one; always use the exact next_cursor value from the previous page's response, or omit cursor entirely to start from page one.

Resetting all data

Destructive — deletes the PostgreSQL volume entirely, including anything not backed up:

docker compose down -v
docker compose up -d --build
docker compose exec -T postgres psql -U rai -d rai \
  < packages/raise-server/scripts/seed_dev.sql

Where to look next

  • Server application logs: docker compose logs server
  • PostgreSQL logs: docker compose logs postgres
  • Live shell in the server container: docker compose exec server bash
  • Live psql session: docker compose exec postgres psql -U rai -d rai

If none of the above resolves it, capture docker compose logs output (both services) and the exact command that triggered the failure before filing an issue — self-hosted support requests without logs are rarely actionable.