paperclipai/paperclip · warning · Error

Claude CLI usage probe ended before rendering usage.

Error message

Claude CLI usage probe ended before rendering usage.

What it means

Thrown by captureClaudeCliUsageText on the success path: execFileAsync completed without error, but cleanTerminalText(output) failed usageOutputLooksComplete (no 'current session' + week/extra + percentage pattern, and no recognized error marker). The probe ran the scripted /usage interaction but the rendered output was incomplete or unrecognizable, so it cannot be trusted as quota data.

Source

Thrown at packages/adapters/claude-local/src/server/quota.ts:451

  const claudeCommand = "claude --tools \"\"";
  if (process.platform === "darwin") {
    return `${feed} | script -q /dev/null ${claudeCommand}`;
  }
  return `${feed} | script -q -e -f -c ${quoteForShell(claudeCommand)} /dev/null`;
}

export async function captureClaudeCliUsageText(timeoutMs = 12_000): Promise<string> {
  const command = buildClaudeCliShellProbeCommand();
  try {
    const { stdout, stderr } = await execFileAsync("sh", ["-c", command], {
      env: createClaudeQuotaEnv(),
      timeout: timeoutMs,
      maxBuffer: 8 * 1024 * 1024,
    });
    const output = `${stdout}${stderr}`;
    const cleaned = cleanTerminalText(output);
    if (usageOutputLooksComplete(cleaned)) return output;
    throw new Error("Claude CLI usage probe ended before rendering usage.");
  } catch (error) {
    const stdout =
      typeof error === "object" && error !== null && "stdout" in error && typeof error.stdout === "string"
        ? error.stdout
        : "";
    const stderr =
      typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string"
        ? error.stderr
        : "";
    const output = `${stdout}${stderr}`;
    const cleaned = cleanTerminalText(output);
    if (usageOutputLooksComplete(cleaned)) return output;
    if (usageOutputLooksRelevant(cleaned)) {
      throw new Error("Claude CLI usage probe ended before rendering usage.");
    }
    throw error instanceof Error ? error : new Error(String(error));
  }
}

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Retry the probe — timing-sensitive TUI interactions are flaky; the probe is designed to be re-run.
  2. Confirm `claude` launches and renders /usage interactively on the same host and user account.
  3. Ensure the quota probe runs in an environment with a working pty (the `script` binary present, TERM set).
  4. Prefer the OAuth quota path (fetchClaudeQuota) when available; the CLI probe is a fallback.
Defensive patterns

Strategy: retry

Try / catch

let text;
for (let i = 0; i < 3; i++) {
  try {
    text = await captureClaudeCliUsageText();
    break;
  } catch (err) {
    if (err.message !== "Claude CLI usage probe ended before rendering usage.") throw err;
  }
}

Prevention

When it happens

Trigger: The shell probe (sleep 2; printf '/usage'; sleep 6; ...) ran under `claude --tools ""` via `script`, finished within the 12s timeout, but the terminal output never rendered a complete usage panel — e.g. the /usage keystroke arrived before the TUI was ready, or the panel rendered after the ESC/Ctrl-C sequence.

Common situations: Slow machine where the 2s/6s sleeps in the probe are too short for the Claude TUI to be ready; a Claude CLI version with a different startup/usage render timing; missing TERM/terminal capabilities under the quota env; running under a non-tty where `script` behaves differently.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/0e425418a80add29. Report an issue: GitHub.