langchain-ai/deepagents · critical · RuntimeError

Server did not become healthy within {timeout}s

Error message

Server did not become healthy within {timeout}s

What it means

`wait_for_server_healthy` polls the server's `/ok` health endpoint until a timeout expires; if the server never returns HTTP 200, it raises `RuntimeError` including the last HTTP status or connection exception for diagnosis.

Source

Thrown at libs/code/deepagents_code/client/launch/server.py:355

            try:
                resp = await client.get(health_url, timeout=2)
                if resp.status_code == 200:  # noqa: PLR2004
                    logger.info("Server is healthy at %s", url)
                    return
                last_status = resp.status_code
                logger.debug("Health check returned status %d", resp.status_code)
            except (httpx.TransportError, OSError) as exc:
                logger.debug("Health check attempt failed: %s", exc)
                last_exc = exc

            await asyncio.sleep(poll_interval)

    msg = f"Server did not become healthy within {timeout}s"
    if last_status is not None:
        msg += f" (last status: {last_status})"
    elif last_exc is not None:
        msg += f" (last error: {last_exc})"
    raise RuntimeError(msg)


# ---------------------------------------------------------------------------
# Server command / env construction
# ---------------------------------------------------------------------------


def _build_server_cmd(config_path: Path, *, host: str, port: int) -> list[str]:
    """Build the `langgraph dev` command line.

    Args:
        config_path: Path to the `langgraph.json` config file.
        host: Host to bind.
        port: Port to bind.

    Returns:
        Command argv list.
    """

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Increase the startup timeout to accommodate slow first boot
  2. Check the appended `last status`/`last error` for whether the endpoint refused, 404'd, or hung
  3. Confirm the server's bound host/port matches the launcher configuration
  4. Inspect server logs for startup hangs (DB migrations, network calls) and fix the blocking step
  5. Verify nothing else occupies the port and no firewall blocks localhost

Example fix

// before
start(timeout=30)  # slow cold boot exceeds 30s
// after
start(timeout=120)  # allow time for first-time dependency install
Defensive patterns

Strategy: retry

Validate before calling

import socket
with socket.socket() as s:
    s.settimeout(2)
    try:
        s.connect((host, port))
        print("port reachable")
    except OSError as e:
        print(f"endpoint unreachable before start: {e}")

Type guard

def endpoint_pollable(host: str, port: int) -> bool:
    import socket
    try:
        with socket.socket() as s:
            s.settimeout(2)
            s.connect((host, port))
        return True
    except OSError:
        return False

Try / catch

try:
    await wait_for_server_healthy(url, timeout=timeout)
except RuntimeError as e:
    if "did not become healthy" in str(e):
        logger.warning("health timeout (%s); retrying with longer budget", e)
        await wait_for_server_healthy(url, timeout=timeout * 3)
    else:
        raise

Prevention

When it happens

Trigger: Server process is alive but never healthy within `timeout` seconds: slow startup (heavy imports/first-time dependency install), health endpoint bound to a different host/port than polled, server hung on startup, or firewall blocking loopback connections.

Common situations: Cold start with large dependency tree on slow machine, wrong host binding (server on 127.0.0.1, launcher polling another interface), port already occupied by another process answering slowly, or container networking issues.

Understand the failure class

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/4a1438ec9cac81a0. Report an issue: GitHub.