headroomlabs-ai/headroom · error · RuntimeError
`{' '.join(cmd)}` did not emit a final `result` event. First
Error message
`{' '.join(cmd)}` did not emit a final `result` event. First {_MAX_SNIPPET_LEN} chars of stdout:
{stdout_snippet} What it means
Raised by the streaming analyzer when claude-cli exited cleanly (exit 0) but no JSON event with type=="result" was ever seen on stdout. The result event is the only place the assistant's answer lives, so without it there is nothing to parse; the message includes the first _MAX_SNIPPET_LEN chars of captured stdout for diagnosis.
Source
Thrown at headroom/learn/analyzer.py:769
result_text = event.get("result")
if isinstance(result_text, str):
final_result = result_text
else:
stderr_lines.append(line)
proc.wait()
if proc.returncode != 0:
stderr_blob = "".join(stderr_lines)[:_MAX_SNIPPET_LEN]
raise RuntimeError(f"`{' '.join(cmd)}` failed (exit {proc.returncode}):\n{stderr_blob}")
stderr_blob = "".join(stderr_lines)
if stderr_blob.strip():
logger.debug("CLI stderr (exit 0): %s", stderr_blob[:_MAX_SNIPPET_LEN])
if final_result is None:
stdout_snippet = "".join(stdout_lines)[:_MAX_SNIPPET_LEN]
raise RuntimeError(
f"`{' '.join(cmd)}` did not emit a final `result` event. "
f"First {_MAX_SNIPPET_LEN} chars of stdout:\n{stdout_snippet}"
)
try:
return _strip_fenced_json(final_result)
except json.JSONDecodeError as exc:
snippet = final_result[:_MAX_SNIPPET_LEN]
raise RuntimeError(
f"`{' '.join(cmd)}` returned unparseable output. "
f"First {_MAX_SNIPPET_LEN} chars:\n{snippet}"
) from exc
def _parse_stream_event(line: str) -> dict | None:
"""Parse one line of claude-cli stream-json output, returning None on junk."""
line = line.strip()
if not line:View on GitHub (pinned to 322425c43b)
Solutions
- Inspect the stdout snippet in the message — if it shows assistant text but no result frame, update claude-cli (`claude update`) to pick up stream fixes.
- Retry the run; transient empty responses from the backend are a known shape.
- Shrink the digest being analyzed (learn fewer conversations at once) so the response is shorter and the result event is not truncated.
- Switch to a different backend with --model <litellm-model-name> to rule out claude-cli-specific behavior.
- Report with debug logs if it persists on the latest CLI version.
Example fix
# before headroom learn # exit 0 but 'did not emit a final `result` event' # after claude update # or: headroom learn --model gpt-4o # different backend
Defensive patterns
Strategy: retry
Try / catch
last_err = None
for attempt in range(2):
try:
result = run_learn(...)
break
except RuntimeError as e:
if "did not emit a final `result` event" in str(e):
last_err = e
continue
raise
else:
raise SystemExit(f"backend dropped result event twice; switch --model: {last_err}") Prevention
- Pin a known-good claude-cli version in CI instead of floating latest.
- Keep learn digests small so responses finish well within limits.
- When this fires once, retry before investigating — transient empty completions are the common case.
When it happens
Trigger: Calling the claude-cli with --output-format stream-json where the model returns an empty response, the CLI emits only system/assistant events and drops the final result event, the stream is truncated by a kill, or an unexpected claude-cli version changes the event schema so _parse_stream_event never matches type 'result'.
Common situations: claude-cli version drift changing stream-json event shapes; empty model responses (empty conversation or prompt filtered); upstream CLI bug losing the result event on long outputs; running against a litellm-proxied model that ends the stream without a result frame.
Related errors
- Error: {e}
- `{' '.join(cmd)}` produced no output for {idle_cap}s. Check
- `{' '.join(cmd)}` failed (exit {proc.returncode}): {stderr_b
- `{' '.join(cmd)}` returned unparseable output. First {_MAX_S
- {env_var} must be a JSON object of header name/value strings
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/5e9cccc654cd1d91.
Report an issue: GitHub.