Skip to main content
All CostHQ errors follow a consistent JSON shape so your agent scripts can handle them programmatically without brittle string matching. Whether a command fails because there is no active session or because a model is unknown, the structure is always the same — only error.code changes.

Error Shape

{
  "schemaVersion": 1,
  "CostHQVersion": "3.1.1",
  "error": {
    "code": "no_active_session",
    "message": "No active session"
  }
}
The schemaVersion and CostHQVersion fields are present on every response, including errors. Parse error.code to branch your logic. Never branch on error.message — it is human-readable prose that may change between versions.

Exit Codes

CodeMeaning
0Success
1Error (always, including in --json mode)
There is no ambiguity: any non-zero exit code means the command failed and an error object is present in the JSON output.

Error Codes

CodeWhen it occursHow to handle
session_activecs start called while a session is already runningUse --close-stale to auto-close the stale session, or --resume to continue it
no_active_sessioncs end or cs log-ai called with no active sessionRun cs status --json first to confirm session state
session_not_foundcs show or cs end -s <id> called with an invalid session IDVerify the ID with cs list --json
missing_tokenscs log-ai called without token counts or a manual costProvide --prompt-tokens + --completion-tokens, or -c <cost>
unknown_modelModel is not in the built-in pricing table and no -c flag was givenAdd -c <cost> explicitly, or register custom pricing with cs pricing set

Parsing Error Codes

import { execSync } from 'child_process';

let output: string;
try {
  output = execSync('cs status --json', { encoding: 'utf8' });
} catch (err: any) {
  output = err.stdout; // --json errors still write to stdout, exit code 1
}

const result = JSON.parse(output);
if (result.error) {
  switch (result.error.code) {
    case 'session_active':
      // Handle already-running session
      break;
    case 'no_active_session':
      // Start a session first
      break;
    case 'session_not_found':
      // Verify the session ID
      break;
  }
}
When a command exits with code 1, execSync throws. The error object’s .stdout property still contains the full --json error payload — read it from there, not from stderr.

Failsafe Pattern for Agents

Check that cs is installed before attempting any tracking. If it is absent, skip gracefully rather than blocking your agent’s primary task.
# Check cs is installed before any tracking (Linux / macOS)
which cs >/dev/null 2>&1 || { echo "costhq not installed, skipping tracking"; exit 0; }

# Windows equivalent
where cs >nul 2>&1 || (echo costhq not installed, skipping tracking && exit /b 0)
The same check in Node.js:
import { execSync } from 'child_process';

function isCostHQInstalled(): boolean {
  try {
    const cmd = process.platform === 'win32' ? 'where cs' : 'which cs';
    execSync(cmd, { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}

if (!isCostHQInstalled()) {
  console.warn('costhq not installed — skipping session tracking');
}
Never string-compare error.message. The human-readable message text may change between CostHQ versions. Always branch on error.code, which is part of the stable contract.