Graphify-Labs/graphify · error · RuntimeError

claude -p produced unparseable JSON envelope: {exc}; first 5

Error message

claude -p produced unparseable JSON envelope: {exc}; first 500 chars of stdout: {stdout[:500]!r}

What it means

Raised by `_claude_cli_envelope` when `json.loads(stdout)` fails on the output of `claude -p --output-format json`. graphify expects the CLI's stdout to be a single JSON object (older CLIs) or a JSON array of streamed events (newer CLIs ≥ ~2.1); anything unparseable — interleaved warnings, banners, partial writes — triggers this error, including the first 500 chars of what was actually received to aid diagnosis.

Source

Thrown at graphify/llm.py:1365

            file=sys.stderr,
        )
        result["finish_reason"] = "length"
    return result


def _claude_cli_envelope(stdout: str) -> dict:
    """Parse the JSON returned by `claude -p --output-format json`.

    Older Claude Code CLI versions returned a single envelope object. Newer
    versions (>= ~2.1) emit a JSON ARRAY of streamed event objects (a system
    init event, assistant turns, an optional rate_limit_event, and a final
    {"type":"result"} object). Normalize both shapes to the result dict that
    carries `result`, `usage`, `modelUsage`, and `stop_reason`.
    """
    try:
        envelope = json.loads(stdout)
    except json.JSONDecodeError as exc:
        raise RuntimeError(
            f"claude -p produced unparseable JSON envelope: {exc}; "
            f"first 500 chars of stdout: {stdout[:500]!r}"
        ) from exc
    if isinstance(envelope, list):
        result_events = [
            e for e in envelope
            if isinstance(e, dict) and e.get("type") == "result"
        ]
        if result_events:
            return result_events[-1]
        if envelope and isinstance(envelope[-1], dict):
            return envelope[-1]
        raise RuntimeError(
            "claude -p returned a JSON array with no result object; "
            f"first 500 chars of stdout: {stdout[:500]!r}"
        )
    return envelope

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. Update Claude Code CLI to a current version (`claude update` or reinstall via npm) — the envelope formats supported cover recent releases.
  2. Run `claude -p --output-format json "hi"` manually and confirm stdout is pure JSON; if not, find what is polluting it (shell profile banners, plugins, progress bars).
  3. Authenticate first: run `claude` once interactively so the headless `-p` mode doesn't emit login prose.
  4. If the run timed out, raise GRAPHIFY_API_TIMEOUT / --api-timeout so the full envelope is flushed.
Defensive patterns

Strategy: validation

Validate before calling

import json, subprocess

def claude_cli_emits_json() -> bool:
    p = subprocess.run(["claude", "-p", "--output-format", "json", "say ok"],
                       capture_output=True, text=True, timeout=60)
    try:
        json.loads(p.stdout)
        return True
    except json.JSONDecodeError:
        return False

assert claude_cli_emits_json(), "claude CLI stdout is not pure JSON; update/reinstall the CLI"

Try / catch

try:
    result = extract_files_direct(files, root, backend="claude-cli")
except RuntimeError as e:
    if "unparseable JSON envelope" in str(e):
        print(f"CLI stdout corrupted: {e}"); raise
    raise

Prevention

When it happens

Trigger: Running the `claude-cli` backend where `claude -p` writes non-JSON to stdout: a CLI version with a changed output format, ANSI/progress output mixed into stdout, a truncated run killed by the subprocess timeout, or plugin/startup messages the CLI prints before the JSON envelope.

Common situations: Upgrading (or pinning an old) Claude Code CLI whose output format graphify doesn't recognize; running in a terminal/wrapper that appends text to stdout; `claude` not authenticated so it prints a login prompt instead of JSON; stdout truncated when the process hits the `_resolve_api_timeout()` bound.

Related errors


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