opendatalab/MinerU · critical · RuntimeError

Local worker {server_id} exited before becoming healthy

Error message

Local worker {server_id} exited before becoming healthy

What it means

RuntimeError raised in router.py by LocalWorker.wait_until_ready: the subprocess spawned for a local API worker terminated (process.poll() is not None) before its /health endpoint ever returned 200. The worker process died during startup — the most information-rich failure in the local-worker lifecycle because the subprocess's own stderr usually holds the root cause.

Source

Thrown at mineru/cli/router.py:462

        self.process_group_id = self.process.pid

        try:
            await self.wait_until_ready(client)
        except Exception:
            self.stop()
            raise

    async def wait_until_ready(
        self,
        client: httpx.AsyncClient,
        timeout_seconds: float = LOCAL_API_STARTUP_TIMEOUT_SECONDS,
    ) -> None:
        assert self.base_url is not None
        deadline = asyncio.get_running_loop().time() + timeout_seconds
        last_error: str | None = None
        while asyncio.get_running_loop().time() < deadline:
            if self.process is not None and self.process.poll() is not None:
                raise RuntimeError(f"Local worker {self.server_id} exited before becoming healthy")
            try:
                response = await client.get(f"{self.base_url}{HEALTH_ENDPOINT}")
                if response.status_code == 200:
                    return
                last_error = response_detail(response)
            except httpx.HTTPError as exc:
                last_error = str(exc)
            await asyncio.sleep(TASK_STATUS_POLL_INTERVAL_SECONDS)

        message = f"Timed out waiting for local worker {self.server_id} to become healthy"
        if last_error:
            message = f"{message}: {last_error}"
        raise RuntimeError(message)

    async def restart(self, client: httpx.AsyncClient) -> None:
        self.stop()
        await self.start(client)

View on GitHub (pinned to 4fe4bde114)

Solutions

  1. Reproduce the worker startup manually (the same command the router spawns) and read the traceback it prints — that is the real error.
  2. Fix the environment: reinstall dependencies (pip install -U mineru ...), verify CUDA/driver compatibility, free the port.
  3. Check dmesg/systemd logs for OOM kills if there is no traceback; raise memory limits or preload fewer models.
  4. Validate the install with the mineru CLI sanity commands before running the router.

Example fix

# before
router start -> RuntimeError: Local worker 1 exited before becoming healthy

# after (diagnose: run the worker command directly)
# python -m mineru.cli.fast_api --host 127.0.0.1 --port 8001
# -> ModuleNotFoundError: No module named 'magic_pdf'
# pip install -U mineru[core] && retry
Defensive patterns

Strategy: try-catch

Validate before calling

# smoke-test the worker command before letting the router spawn it
import subprocess, sys
r = subprocess.run([sys.executable, '-m', 'mineru.cli.fast_api', '--help'],
                   capture_output=True, text=True, timeout=60)
assert r.returncode == 0, r.stderr[-2000:]

Try / catch

try:
    await worker.wait_until_ready(client)
except RuntimeError as exc:
    if 'exited before becoming healthy' in str(exc):
        stderr = read_worker_log(worker)  # subprocess stderr holds the root cause
        raise RuntimeError(f'worker startup crash: {stderr[-2000:]}') from exc
    raise

Prevention

When it happens

Trigger: Worker process crashes on import (missing dependency, incompatible torch/CUDA); model files missing or corrupted so startup aborts; port already in use causing immediate exit; Python environment mismatch (worker spawned with a different interpreter); OOM kill during model preload.

Common situations: Fresh installs with incomplete dependencies; GPU driver/CUDA mismatches; two services contending for the same port; container memory limits killing the worker during model load; upgrading mineru leaving stale caches.

Related errors


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