{"record":{"id":"c0483a35f2656eb3","repo":"headroomlabs-ai/headroom","slug":"proxy-failed-to-start-on-port-port-within-timeo","errorCode":null,"errorMessage":"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.","messagePattern":"Proxy failed to start on port (.+?) within (.+?) seconds\\. Set (.+?) to a larger number of seconds for slow startup\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"headroom/cli/wrap.py","lineNumber":808,"sourceCode":"        # Wait for proxy to be ready.\n        # ML components (Kompress, Magika, Tree-sitter) load synchronously before\n        # uvicorn binds the port. On slower machines this can take 20-30 seconds.\n        for _i in range(timeout_seconds):\n            time.sleep(1)\n            if _check_proxy(port):\n                click.echo(f\"  Logs: {log_path}\")\n                return proc\n            # Check if process died\n            if proc.poll() is not None:\n                # Read last few lines of log for error context\n                try:\n                    tail = _read_text(stdio_log_path)[-500:]\n                except Exception:\n                    tail = \"(no log output)\"\n                raise RuntimeError(f\"Proxy exited with code {proc.returncode}: {tail}\")\n\n        proc.kill()\n        raise RuntimeError(\n            f\"Proxy failed to start on port {port} within {timeout_seconds} seconds. \"\n            f\"Set {_WRAP_PROXY_TIMEOUT_ENV} to a larger number of seconds for slow startup.\"\n        )\n    finally:\n        stdio_log_file.close()\n\n\n# CLI context tools (rtk, lean-ctx) were removed from Headroom. The selector is\n# kept only long enough to fail loudly: it lives in shell profiles, scripts and\n# CI jobs, and silently ignoring it would look like Headroom had stopped working.\n# See :mod:`headroom.context_tool_cleanup`, which uninstalls what they left behind.\n_RETIRED_CONTEXT_TOOL_ENV = \"HEADROOM_CONTEXT_TOOL\"\n_RETIRED_CONTEXT_TOOL_MESSAGE = (\n    \"CLI context tools (rtk, lean-ctx) have been removed from Headroom: they \"\n    \"rewrote shell commands through a third-party binary Headroom no longer \"\n    \"manages. Drop --context-tool / --no-context-tool and unset \"\n    f\"{_RETIRED_CONTEXT_TOOL_ENV}; `headroom wrap` uninstalls what they left \"\n    \"behind automatically.\"","sourceCodeStart":790,"sourceCodeEnd":826,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/cli/wrap.py#L790-L826","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Raise the timeout: export HEADROOM_WRAP_PROXY_TIMEOUT=120 (must be a plain positive integer)","Check the proxy log (proxy.log and the stdio log) to see whether startup is progressing or hung on a network fetch","Reduce startup cost: pre-warm caches, close heavy competing processes, or pin to a lighter backend","If it hangs every time (not just slowly), inspect the log for a blocked health check or missing dependency and fix that root cause"],"exampleFix":"# before\nexport HEADROOM_WRAP_PROXY_TIMEOUT=5   # too tight; proxy killed at 5s\nheadroom wrap claude\n\n# after\nexport HEADROOM_WRAP_PROXY_TIMEOUT=120\nheadroom wrap claude","handlingStrategy":"retry","validationCode":"import os, time, urllib.request\n\ndef proxy_healthy(port: int) -> bool:\n    try:\n        urllib.request.urlopen(f\"http://127.0.0.1:{port}/health\", timeout=2)\n        return True\n    except OSError:\n        return False\n\n# budget generously on slow machines before launching the wrap\nos.environ.setdefault(\"HEADROOM_WRAP_PROXY_TIMEOUT\", \"120\")","typeGuard":null,"tryCatchPattern":"for attempt in range(2):\n    try:\n        proc = start_proxy()\n        break\n    except RuntimeError as e:\n        if \"failed to start on port\" in str(e) and attempt == 0:\n            os.environ[\"HEADROOM_WRAP_PROXY_TIMEOUT\"] = \"180\"  # widen and retry once\n            continue\n        raise","preventionTips":["Set HEADROOM_WRAP_PROXY_TIMEOUT=120 on cold or constrained machines","Pre-warm heavy dependencies once so later starts are fast","Distinguish slow start (this error) from crash (exit-code error) before tuning the timeout"],"tags":["timeout","proxy","startup","performance","environment-variables","headroom"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}