{"record":{"id":"a634caa998c37a89","repo":"Graphify-Labs/graphify","slug":"claude-p-exited-proc-returncode-detail-500","errorCode":null,"errorMessage":"claude -p exited {proc.returncode}: {detail[:500]}","messagePattern":"claude -p exited (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"graphify/llm.py","lineNumber":1577,"sourceCode":"    # that framing; the user-turn prompt above stays as the fallback for older\n    # CLIs that predate the flag.\n    if _claude_cli_supports_json_schema(claude_cmd):\n        cli_args.extend([\"--json-schema\", _EXTRACTION_JSON_SCHEMA])\n    proc = subprocess.run(\n        cli_args,\n        input=combined_message,\n        capture_output=True,\n        text=True,\n        encoding=\"utf-8\",  # Force UTF-8 — prevents UnicodeEncodeError on Windows cp1252\n        errors=\"replace\",  # Tolerate non-UTF-8 bytes (e.g. GBK/cp936 from claude.cmd on Chinese Windows)\n        timeout=_resolve_api_timeout(),\n        check=False,\n        **_no_window_kwargs(),\n    )\n    cli_error = _claude_cli_error(proc.stdout)\n    if proc.returncode != 0:\n        detail = proc.stderr.strip() or cli_error or \"(no stderr, no error envelope)\"\n        raise RuntimeError(f\"claude -p exited {proc.returncode}: {detail[:500]}\")\n    if cli_error:\n        raise RuntimeError(f\"claude -p reported an error: {cli_error[:500]}\")\n\n    envelope = _claude_cli_envelope(proc.stdout)\n\n    # When --json-schema is in effect the CLI puts the CONSTRAINED object in the\n    # `structured_output` envelope field; `result` stays the model's discretionary\n    # text, which on a \"reporting\" turn is prose even with the flag set (verified\n    # live on Claude Code 2.1.185). Prefer the structured channel and route it\n    # through the same _parse_llm_json normalizer; fall back to parsing `result`\n    # for older CLIs that don't emit structured_output (#2076 review).\n    structured = envelope.get(\"structured_output\")\n    if isinstance(structured, dict):\n        raw_content = json.dumps(structured)\n    else:\n        raw_content = envelope.get(\"result\", \"\")\n    result = _parse_llm_json(raw_content or \"{}\")\n    usage = envelope.get(\"usage\") or {}","sourceCodeStart":1559,"sourceCodeEnd":1595,"githubUrl":"https://github.com/Graphify-Labs/graphify/blob/7fe58b0b0f3873be9a21c30106b8b8527c353aa6/graphify/llm.py#L1559-L1595","documentation":"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.","triggerScenarios":"`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).","commonSituations":"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.","solutions":["Read the 500-char detail in the message — it names the actual CLI error (auth, flag, network).","Run `claude` once interactively in the same user context to (re)authenticate.","Update the CLI to match the flags graphify passes, or update graphify if the CLI just changed its interface.","Reproduce manually with `claude -p --output-format json < prompt.txt` to see full stderr."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import subprocess\n\ndef claude_cli_healthy() -> bool:\n    p = subprocess.run([\"claude\", \"-p\", \"--output-format\", \"json\", \"reply ok\"],\n                       capture_output=True, text=True)\n    return p.returncode == 0","typeGuard":null,"tryCatchPattern":"try:\n    result = extract_files_direct(files, root, backend=\"claude-cli\")\nexcept RuntimeError as e:\n    if \"claude -p exited\" in str(e):\n        # surface the CLI's own detail, decide auth vs crash\n        log.error(\"claude-cli failed: %s\", e)\n        raise","preventionTips":["Complete interactive `claude` login before headless runs; refresh in CI before tokens expire.","Pin CLI version and update graphify together to keep the flag set compatible.","Smoke-test `claude -p` in the same user context as the automation."],"tags":["claude-cli","subprocess","authentication","exit-code"],"backgroundTag":null,"analyzedSha":"7fe58b0b0f3873be9a21c30106b8b8527c353aa6","analyzedAt":"2026-08-14T19:23:21.323Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}