opendatalab/MinerU · critical · RuntimeError

No healthy upstream MinerU API servers are available

Error message

No healthy upstream MinerU API servers are available

What it means

Raised at router startup when the WorkerPool health check reports no healthy upstream MinerU API servers. The router refuses to start (and shuts down the registry, worker pool, and http client) because every configured upstream failed its health probe. The message may come from the health payload's 'error' key, defaulting to this string.

Source

Thrown at mineru/cli/router.py:999


async def startup_router_state(app: FastAPI, settings: RouterSettings) -> None:
    http_client = httpx.AsyncClient(
        timeout=build_http_timeout(),
        follow_redirects=True,
    )
    worker_pool = WorkerPool(settings, http_client)
    registry = RouterTaskRegistry(
        task_retention_seconds=settings.task_retention_seconds,
        cleanup_interval_seconds=settings.task_cleanup_interval_seconds,
    )

    try:
        await registry.start()
        await worker_pool.start()
        healthy, payload = worker_pool.health_payload()
        if not healthy:
            raise RuntimeError(
                payload.get(
                    "error",
                    "No healthy upstream MinerU API servers are available",
                )
            )
    except Exception:
        await registry.shutdown()
        await worker_pool.shutdown()
        await http_client.aclose()
        raise

    app.state.http_client = http_client
    app.state.worker_pool = worker_pool
    app.state.router_task_registry = registry


async def shutdown_router_state(app: FastAPI) -> None:
    registry = getattr(app.state, "router_task_registry", None)

View on GitHub (pinned to 4fe4bde114)

Solutions

  1. Start or fix the upstream MinerU API servers and verify each /health endpoint returns healthy with curl before starting the router
  2. Correct the server URL list in the router configuration (scheme, host, port)
  3. If servers are slow to boot, start them first or add readiness checks so the router starts after upstreams are healthy
  4. Check network/DNS/firewall between the router host and each upstream server

Example fix

# before
MINERU_SERVER_URLS=http://localhost:8000  # server not running

# after
# start upstream first, verify, then run router
curl -fsS http://localhost:8000/health
MINERU_SERVER_URLS=http://localhost:8000 mineru-api-router
Defensive patterns

Strategy: validation

Validate before calling

import httpx

def upstreams_healthy(server_urls: list[str], timeout: float = 5.0) -> bool:
    with httpx.Client(timeout=timeout) as c:
        return all(
            c.get(f"{u.rstrip('/')}/health").status_code == 200
            for u in server_urls
        )

Try / catch

try:
    app = create_router_app(settings)
except RuntimeError as exc:
    if "No healthy upstream" in str(exc):
        log.error("upstreams down; not starting router")
    raise

Prevention

When it happens

Trigger: Calling create_app/router startup with MINERU_SERVER_URLS (or equivalent settings) pointing at servers that are down, unreachable, or return non-healthy /health responses; worker_pool.health_payload() returns healthy=False during lifespan startup.

Common situations: Upstream MinerU API processes not started yet; wrong host/port in server list; firewall or DNS blocking the health endpoint; upstream containers still booting when the router starts; all servers previously marked unhealthy.

Related errors


AI-assisted analysis of opendatalab/MinerU@4fe4bde114 (2026-08-14). Data as JSON: /api/errors/9df6a45066225501. Report an issue: GitHub.