Graphify-Labs/graphify · error · RuntimeError

claude -p reported an error: {cli_error[:500]}

Error message

claude -p reported an error: {cli_error[:500]}

What it means

Raised when `claude -p` exited 0 but the stdout JSON envelope carries an error (the `_claude_cli_error` extraction found `is_error` in the envelope). Per the adjacent comment, the CLI reports API failures such as rate limits and auth errors in the stdout JSON with `is_error: true` while leaving stderr empty — and on rate limits it still exits 0 — so exit-code checks alone miss it. The CLI's own error text is included (truncated to 500 chars).

Source

Thrown at graphify/llm.py:1579

    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 {}
    result["input_tokens"] = (
        int(usage.get("input_tokens", 0) or 0)

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. If the message says rate limit: back off and retry — add spacing between extraction calls or retry after the window resets (graphify's chunk-level retry/skip can also absorb it).
  2. If auth-related: re-run `claude` interactively to refresh credentials.
  3. Reduce parallelism / batch size of the graphify run to stay under limits.
  4. Inspect the full envelope by reproducing with `claude -p --output-format json` to confirm which limit tripped.
Defensive patterns

Strategy: retry

Try / catch

import time
for attempt in range(4):
    try:
        result = extract_files_direct(chunk, root, backend="claude-cli")
        break
    except RuntimeError as e:
        if "reported an error" not in str(e) or attempt == 3:
            raise
        if "rate" in str(e).lower():
            time.sleep(60 * (attempt + 1))  # rate limit: back off
        else:
            raise

Prevention

When it happens

Trigger: Hitting Anthropic API rate limits or an auth/API error during a `claude-cli` extraction: exit code 0, stderr empty, envelope `is_error: true`. Typical during large batch extractions that fire many `claude -p` calls in quick succession.

Common situations: Bulk graphify runs over many chunks exceeding the account's request/token rate limit; subscription usage caps; expired credentials after 0-exit success of previous runs; org-level throttling.

Related errors


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