headroomlabs-ai/headroom · error · RuntimeError

Proxy failed to start on port {port} within {timeout_seconds

Error message

Proxy failed to start on port {port} within {timeout_seconds} seconds. Set {_WRAP_PROXY_TIMEOUT_ENV} to a larger number of seconds for slow startup.

What it means

Headroom spawns the proxy and polls its health endpoint once per second for timeout_seconds (from HEADROOM_WRAP_PROXY_TIMEOUT or the default). If the timeout elapses while the process is still alive but not yet healthy, Headroom kills the child (proc.kill()) and raises this RuntimeError, suggesting the timeout env var for slow machines. Unlike the 'exited with code' error, the process here was alive but unresponsive/slow.

Source

Thrown at headroom/cli/wrap.py:808

        # Wait for proxy to be ready.
        # ML components (Kompress, Magika, Tree-sitter) load synchronously before
        # uvicorn binds the port. On slower machines this can take 20-30 seconds.
        for _i in range(timeout_seconds):
            time.sleep(1)
            if _check_proxy(port):
                click.echo(f"  Logs: {log_path}")
                return proc
            # Check if process died
            if proc.poll() is not None:
                # Read last few lines of log for error context
                try:
                    tail = _read_text(stdio_log_path)[-500:]
                except Exception:
                    tail = "(no log output)"
                raise RuntimeError(f"Proxy exited with code {proc.returncode}: {tail}")

        proc.kill()
        raise RuntimeError(
            f"Proxy failed to start on port {port} within {timeout_seconds} seconds. "
            f"Set {_WRAP_PROXY_TIMEOUT_ENV} to a larger number of seconds for slow startup."
        )
    finally:
        stdio_log_file.close()


# CLI context tools (rtk, lean-ctx) were removed from Headroom. The selector is
# kept only long enough to fail loudly: it lives in shell profiles, scripts and
# CI jobs, and silently ignoring it would look like Headroom had stopped working.
# See :mod:`headroom.context_tool_cleanup`, which uninstalls what they left behind.
_RETIRED_CONTEXT_TOOL_ENV = "HEADROOM_CONTEXT_TOOL"
_RETIRED_CONTEXT_TOOL_MESSAGE = (
    "CLI context tools (rtk, lean-ctx) have been removed from Headroom: they "
    "rewrote shell commands through a third-party binary Headroom no longer "
    "manages. Drop --context-tool / --no-context-tool and unset "
    f"{_RETIRED_CONTEXT_TOOL_ENV}; `headroom wrap` uninstalls what they left "
    "behind automatically."

View on GitHub (pinned to 322425c43b)

Solutions

  1. Raise the timeout: export HEADROOM_WRAP_PROXY_TIMEOUT=120 (must be a plain positive integer)
  2. Check the proxy log (proxy.log and the stdio log) to see whether startup is progressing or hung on a network fetch
  3. Reduce startup cost: pre-warm caches, close heavy competing processes, or pin to a lighter backend
  4. If it hangs every time (not just slowly), inspect the log for a blocked health check or missing dependency and fix that root cause

Example fix

# before
export HEADROOM_WRAP_PROXY_TIMEOUT=5   # too tight; proxy killed at 5s
headroom wrap claude

# after
export HEADROOM_WRAP_PROXY_TIMEOUT=120
headroom wrap claude
Defensive patterns

Strategy: retry

Validate before calling

import os, time, urllib.request

def proxy_healthy(port: int) -> bool:
    try:
        urllib.request.urlopen(f"http://127.0.0.1:{port}/health", timeout=2)
        return True
    except OSError:
        return False

# budget generously on slow machines before launching the wrap
os.environ.setdefault("HEADROOM_WRAP_PROXY_TIMEOUT", "120")

Try / catch

for attempt in range(2):
    try:
        proc = start_proxy()
        break
    except RuntimeError as e:
        if "failed to start on port" in str(e) and attempt == 0:
            os.environ["HEADROOM_WRAP_PROXY_TIMEOUT"] = "180"  # widen and retry once
            continue
        raise

Prevention

When it happens

Trigger: Slow proxy startup exceeding the configured timeout: cold Python import of heavy ML/tokenizer modules, slow first-run model downloads, a health endpoint blocked behind a dependency, heavy CPU load, or a timeout env var set too small (e.g. 1-2 seconds). The health check (_check_proxy) never succeeded within the window.

Common situations: First run on a new machine where dependencies warm caches; CI runners with constrained CPU; containerized environments with slow I/O; users who set HEADROOM_WRAP_PROXY_TIMEOUT to a very low value; network filesystems slowing module import.

Understand the failure class

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/c0483a35f2656eb3. Report an issue: GitHub.