JuliusBrussee/caveman · error · RuntimeError

Claude call failed: {e.stderr}

Error message

Claude call failed:
{e.stderr}

What it means

Raised by compress_file's Claude-call helper in the caveman-compress skill when `claude --print` exits nonzero (subprocess.CalledProcessError). The subprocess runs with check=True, capture_output=True, so any nonzero exit — auth failure, rate limit, network error, invalid model config — surfaces here with the child's stderr appended to the message.

Source

Thrown at skills/caveman-compress/scripts/compress.py:223

    # Resolve binary via shutil.which so Windows .cmd/.bat shims (e.g.
    # %APPDATA%\npm\claude.CMD) work without shell=True. On POSIX,
    # shutil.which returns the same absolute path as the implicit lookup,
    # so this is a no-op there. Falls back to bare "claude" if not found
    # on PATH so subprocess raises a clear FileNotFoundError.
    claude_bin = shutil.which("claude") or "claude"
    try:
        result = subprocess.run(
            [claude_bin, "--print"],
            input=prompt,
            text=True,
            capture_output=True,
            check=True,
            encoding="utf-8",
            errors="replace",
        )
        return strip_llm_wrapper(result.stdout.strip())
    except subprocess.CalledProcessError as e:
        raise RuntimeError(f"Claude call failed:\n{e.stderr}")


def build_compress_prompt(original: str) -> str:
    return f"""
Compress this markdown into caveman format.

STRICT RULES:
- Do NOT modify anything inside ``` code blocks
- Do NOT modify anything inside inline backticks
- Preserve ALL URLs exactly
- Preserve ALL headings exactly
- Preserve file paths and commands
- Return ONLY the compressed markdown body — do NOT wrap the entire output in a ```markdown fence or any other fence. Inner code blocks from the original stay as-is; do not add a new outer fence around the whole file.

Only compress natural language.

TEXT:
{original}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Read the stderr embedded in the message — it is the claude CLI's own error and names the real cause (auth, quota, network).
  2. Run `claude --print` manually with a trivial prompt (echo hi | claude --print) to reproduce and confirm auth/network works.
  3. Re-authenticate (claude login / set API key) or wait out the rate limit, then retry the compress command.
  4. Verify the claude binary is on PATH and up to date if stderr shows a usage/flag error (which claude; claude --version).
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil, subprocess

def claude_cli_ready() -> bool:
    if shutil.which("claude") is None:
        return False
    return subprocess.run(["claude", "--print"], input="ping",
                          capture_output=True, text=True).returncode == 0

Try / catch

try:
    compress_file(path)
except RuntimeError as e:
    if "Claude call failed" in str(e):
        # e's tail is the CLI's own stderr: auth/quota/network — fix that, then retry once
        diagnose_and_retry_once(e)
    raise

Prevention

When it happens

Trigger: Running compress.py (file/URL/text condense flows) when the local `claude` CLI is not authenticated, the API key is missing/expired, the account is rate-limited or out of credits, the network is down, or the claude binary version rejects the `--print` invocation.

Common situations: First run on a new machine before `claude` login; expired OAuth session in the CLI; corporate proxy blocking api.anthropic.com; free-tier quota exhausted mid-batch while compressing many files.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/ff3eef3624937621. Report an issue: GitHub.