headroomlabs-ai/headroom · error · RuntimeError

`{' '.join(cmd)}` did not respond within {hard_cap}s. Check

Error message

`{' '.join(cmd)}` did not respond within {hard_cap}s. Check network connectivity, raise HEADROOM_LEARN_CLI_TIMEOUT_SECS, or try a different backend with --model <litellm-model-name>.

What it means

Raised when the CLI subprocess exceeded the hard cap: subprocess.run(..., timeout=hard_cap) raised subprocess.TimeoutExpired and the process was killed. hard_cap defaults to _CLI_TIMEOUT=300s and is overridable via HEADROOM_LEARN_CLI_TIMEOUT_SECS (resolved by _resolve_timeout_secs). The message suggests connectivity checks, raising the cap, or switching backends.

Source

Thrown at headroom/learn/analyzer.py:607

            timeout=hard_cap,
        )
    except FileNotFoundError:
        shim_cmd = _resolve_windows_cli_shim(cmd)
        if shim_cmd is None:
            raise RuntimeError(
                f"`{cmd[0]}` not found in PATH. Install it or use a different backend "
                "with --model <litellm-model-name>."
            ) from None
        cmd = shim_cmd
        try:
            result = run(cmd, input=prompt, capture_output=True, text=True, timeout=hard_cap)
        except FileNotFoundError:
            raise RuntimeError(
                f"`{cmd[0]}` not found in PATH. Install it or use a different backend "
                "with --model <litellm-model-name>."
            ) from None
    except subprocess.TimeoutExpired:
        raise RuntimeError(
            f"`{' '.join(cmd)}` did not respond within {hard_cap}s. "
            "Check network connectivity, raise HEADROOM_LEARN_CLI_TIMEOUT_SECS, "
            "or try a different backend with --model <litellm-model-name>."
        ) from None

    if result.returncode != 0:
        stderr_snippet = (result.stderr or "")[:_MAX_SNIPPET_LEN]
        raise RuntimeError(
            f"`{' '.join(cmd)}` failed (exit {result.returncode}):\n{stderr_snippet}"
        )

    # Log stderr warnings even on success (auth refreshes, deprecation notices).
    if result.stderr and result.stderr.strip():
        logger.debug("CLI stderr (exit 0): %s", result.stderr[:_MAX_SNIPPET_LEN])

    try:
        return _strip_fenced_json(result.stdout)
    except json.JSONDecodeError as exc:

View on GitHub (pinned to 322425c43b)

Solutions

  1. Raise the cap: export HEADROOM_LEARN_CLI_TIMEOUT_SECS=900 (or higher for big digests)
  2. Check the CLI manually with the same prompt to see whether it's genuinely slow or hung (network/auth issue)
  3. Switch to a faster/healthier backend: use the claude-cli streaming path (which has an idle-based cap instead) or an API model via --model <litellm-model-name>

Example fix

# before
headroom learn  # CLI killed at 300s default

# after
export HEADROOM_LEARN_CLI_TIMEOUT_SECS=900
headroom learn
Defensive patterns

Strategy: retry

Validate before calling

import os
cap = int(os.environ.get('HEADROOM_LEARN_CLI_TIMEOUT_SECS', 300))
if cap < 600 and my_digest_is_large:
    os.environ['HEADROOM_LEARN_CLI_TIMEOUT_SECS'] = '900'

Try / catch

for attempt in range(2):
    try:
        return run_learn()
    except RuntimeError as e:
        if 'did not respond within' in str(e) and attempt == 0:
            os.environ['HEADROOM_LEARN_CLI_TIMEOUT_SECS'] = '900'
            continue
        raise

Prevention

When it happens

Trigger: `headroom learn` with a CLI backend (claude/gemini/codex) whose analysis run takes longer than the cap — large session digests, slow model responses, network stalls — and HEADROOM_LEARN_CLI_TIMEOUT_SECS unset or set too low.

Common situations: Huge conversation digests sent for analysis; corporate proxies/rate limits slowing the CLI; the default 300s being lowered by a copied env var; free-tier CLI backends queuing requests.

Understand the failure class

Related errors


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