Graphify-Labs/graphify · error · RuntimeError

claude -p exited {proc.returncode}: {detail[:500]}

Error message

claude -p exited {proc.returncode}: {detail[:500]}

What it means

Raised after `subprocess.run` of `claude -p` returns a non-zero exit code. The detail is stderr if present, otherwise the CLI's own error envelope extracted by `_claude_cli_error(stdout)`, otherwise a placeholder — because the CLI sometimes exits non-zero with empty stderr. Output is truncated to 500 chars. This is a hard CLI failure (auth, bad flags, crash), not a model-level issue.

Source

Thrown at graphify/llm.py:1577

    # that framing; the user-turn prompt above stays as the fallback for older
    # CLIs that predate the flag.
    if _claude_cli_supports_json_schema(claude_cmd):
        cli_args.extend(["--json-schema", _EXTRACTION_JSON_SCHEMA])
    proc = subprocess.run(
        cli_args,
        input=combined_message,
        capture_output=True,
        text=True,
        encoding="utf-8",  # Force UTF-8 — prevents UnicodeEncodeError on Windows cp1252
        errors="replace",  # Tolerate non-UTF-8 bytes (e.g. GBK/cp936 from claude.cmd on Chinese Windows)
        timeout=_resolve_api_timeout(),
        check=False,
        **_no_window_kwargs(),
    )
    cli_error = _claude_cli_error(proc.stdout)
    if proc.returncode != 0:
        detail = proc.stderr.strip() or cli_error or "(no stderr, no error envelope)"
        raise RuntimeError(f"claude -p exited {proc.returncode}: {detail[:500]}")
    if cli_error:
        raise RuntimeError(f"claude -p reported an error: {cli_error[:500]}")

    envelope = _claude_cli_envelope(proc.stdout)

    # When --json-schema is in effect the CLI puts the CONSTRAINED object in the
    # `structured_output` envelope field; `result` stays the model's discretionary
    # text, which on a "reporting" turn is prose even with the flag set (verified
    # live on Claude Code 2.1.185). Prefer the structured channel and route it
    # through the same _parse_llm_json normalizer; fall back to parsing `result`
    # for older CLIs that don't emit structured_output (#2076 review).
    structured = envelope.get("structured_output")
    if isinstance(structured, dict):
        raw_content = json.dumps(structured)
    else:
        raw_content = envelope.get("result", "")
    result = _parse_llm_json(raw_content or "{}")
    usage = envelope.get("usage") or {}

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. Read the 500-char detail in the message — it names the actual CLI error (auth, flag, network).
  2. Run `claude` once interactively in the same user context to (re)authenticate.
  3. Update the CLI to match the flags graphify passes, or update graphify if the CLI just changed its interface.
  4. Reproduce manually with `claude -p --output-format json < prompt.txt` to see full stderr.
Defensive patterns

Strategy: try-catch

Validate before calling

import subprocess

def claude_cli_healthy() -> bool:
    p = subprocess.run(["claude", "-p", "--output-format", "json", "reply ok"],
                       capture_output=True, text=True)
    return p.returncode == 0

Try / catch

try:
    result = extract_files_direct(files, root, backend="claude-cli")
except RuntimeError as e:
    if "claude -p exited" in str(e):
        # surface the CLI's own detail, decide auth vs crash
        log.error("claude-cli failed: %s", e)
        raise

Prevention

When it happens

Trigger: `claude -p ...` exiting non-zero: expired/absent authentication, invalid flags for the installed CLI version, CLI crash, or environment problems (no TTY trust prompt completed, blocked network).

Common situations: Never having run `claude` interactively to log in; OAuth token expiry in long-lived CI; CLI auto-update changing flag semantics; corporate proxies blocking claude.ai endpoints; running in a container where the CLI crashes on startup.

Related errors


AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14). Data as JSON: /api/errors/a634caa998c37a89. Report an issue: GitHub.