Structured Error Handling to Reduce (2026)

The Problem

When Claude Code encounters an unstructured error, it enters a diagnostic loop: reading logs, re-running commands, searching for context, and guessing at fixes. A single unstructured stack trace can trigger 5-10 tool calls (each costing 245+ tokens for Bash, 150+ for Read, plus the response content) before the agent identifies the root cause. This retry-heavy pattern wastes 20,000-80,000 tokens per debugging session – $0.06-$1.20 on Sonnet 4.6 rates. Structured error output gives Claude Code the diagnosis on the first attempt.

Quick Wins (Under 5 Minutes)

  1. Add exit codes to all scripts – use set -euo pipefail in Bash scripts so failures surface immediately with meaningful codes.
  2. Wrap critical commands in structured output – pipe errors through a formatter that outputs JSON with error type, location, and suggested fix.
  3. Add error catalogs to CLAUDE.md – list the 5-10 most common project errors with their fixes so Claude does not need to discover them.
  4. Use --json flags – many CLIs (TypeScript, ESLint, Jest) have JSON output modes that Claude Code parses more efficiently.

Deep Optimization Strategies

Strategy 1: JSON Error Output from Build Tools

Configure build tools to output structured JSON instead of human-readable error messages:

# Unstructured: TypeScript error (Claude must parse free text)
# src/api/handler.ts(42,5): error TS2345: Argument of type 'string'
#   is not assignable to parameter of type 'number'.
# Token cost to diagnose: ~3,000 tokens (read file, find line, understand context)
# Structured: TypeScript with --pretty false and JSON processing
npx tsc --noEmit --pretty false 2>&1 | head -20

Better yet, create a wrapper that produces machine-friendly output:

#!/bin/bash
# scripts/check-types.sh -- structured error output for Claude Code
set -uo pipefail
OUTPUT=$(npx tsc --noEmit --pretty false 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
  ERROR_COUNT=$(echo "$OUTPUT" | grep -c "error TS" || true)
  FIRST_ERROR=$(echo "$OUTPUT" | head -1)
  echo "TYPE_CHECK_FAILED"
  echo "error_count: $ERROR_COUNT"
  echo "first_error: $FIRST_ERROR"
  echo "fix: Review the type mismatch in the reported file and line"
  exit $EXIT_CODE
fi
echo "TYPE_CHECK_PASSED"

Claude Code reads the structured output in one tool call (~400 tokens) instead of 3-5 diagnostic calls (~2,000-4,000 tokens).

Savings: 1,600-3,600 tokens per type error diagnosis

Strategy 2: Error Catalogs in CLAUDE.md

Document known errors so Claude Code does not re-discover solutions:

# CLAUDE.md -- Error Catalog
## Known Errors and Fixes
### ECONNREFUSED on port 5432
- Cause: PostgreSQL not running
- Fix: `brew services start postgresql@16`
- Verify: `pg_isready -h localhost -p 5432`
### "Module not found: @/components"
- Cause: Path alias not configured in tsconfig
- Fix: Check tsconfig.json `paths` includes `"@/*": ["./src/*"]`
- Verify: `npx tsc --noEmit`
### ENOMEM during build
- Cause: Node heap exhaustion on large builds
- Fix: `NODE_OPTIONS=--max-old-space-size=4096 pnpm build`
- Verify: Build completes without OOM

Without this catalog, Claude Code discovering the ECONNREFUSED fix requires: (1) run the failing command (~245 tokens), (2) read the error output (~500 tokens), (3) search for database config (~400 tokens), (4) check if PostgreSQL is running (~245 tokens), (5) attempt the fix (~245 tokens). Total: ~1,635 tokens.

With the catalog: (1) run the failing command (~245 tokens), (2) recognize the error from CLAUDE.md (0 extra tokens – already in context), (3) apply the fix (~245 tokens). Total: ~490 tokens.

Savings: ~1,145 tokens per known error (70% reduction)

Strategy 3: Wrap Commands with Exit Code Contracts

Define clear exit code contracts that Claude Code can interpret without parsing error messages:

#!/bin/bash
# scripts/validate.sh -- bounded error checking with clear exit codes
set -uo pipefail
MAX_ERRORS=50
ERRORS_FOUND=0
# Type checking
if ! npx tsc --noEmit --pretty false > /dev/null 2>&1; then
  echo "FAIL:types"
  ERRORS_FOUND=$((ERRORS_FOUND + 1))
fi
# Lint checking
if ! npx eslint src/ --quiet --max-warnings 0 > /dev/null 2>&1; then
  echo "FAIL:lint"
  ERRORS_FOUND=$((ERRORS_FOUND + 1))
fi
# Test suite
if ! npx jest --silent --bail > /dev/null 2>&1; then
  echo "FAIL:tests"
  ERRORS_FOUND=$((ERRORS_FOUND + 1))
fi
if [ "$ERRORS_FOUND" -gt "$MAX_ERRORS" ]; then
  echo "ERROR: Exceeded maximum error count ($MAX_ERRORS)"
  exit 2
fi
if [ "$ERRORS_FOUND" -gt 0 ]; then
  echo "VALIDATION_FAILED: $ERRORS_FOUND checks failed"
  exit 1
fi
echo "VALIDATION_PASSED"
exit 0

Claude Code reads the one-line output and knows exactly which subsystem failed. No guessing, no log parsing, no extra tool calls.

Savings: 2,000-5,000 tokens per validation cycle

Strategy 4: Structured Test Failure Output

Configure test runners to output failures in a machine-parseable format:

# Jest with JSON reporter -- one tool call to understand all failures
npx jest --json --outputFile=test-results.json 2>/dev/null
# Then Claude reads only the failures:
# {
#   "numFailedTests": 2,
#   "testResults": [{
#     "name": "src/auth.test.ts",
#     "message": "Expected: 200, Received: 401"
#   }]
# }

Add a CLAUDE.md rule to enforce this pattern:

## Testing
- Always run tests with: `npx jest --json --outputFile=test-results.json`
- Read test-results.json for failure details instead of parsing console output
- Fix failures starting with the first failed test file

Savings: 3,000-8,000 tokens per test debugging session (fewer re-runs)

Strategy 5: Error-Specific CLAUDE.md Rules

Direct Claude Code to use structured error handling patterns instead of ad-hoc debugging:

# CLAUDE.md -- Error Handling Protocol
## When a command fails:
1. Read the STRUCTURED output first (look for FAIL:, ERROR:, or JSON error objects)
2. Check the Error Catalog below before investigating further
3. If the error is not in the catalog, run the command with --verbose and read structured output
4. Maximum 2 diagnostic tool calls before applying a fix
5. If the fix fails twice, stop and report the full error context
## Error Response Format (for new error handlers)
All error handlers should output:
- Line 1: ERROR_CODE (machine-readable)
- Line 2: Human description
- Line 3: Suggested fix
- Line 4: Verification command

This rule reduces the average debugging loop from 5-8 tool calls to 2-3, saving 3,000-10,000 tokens per error encounter.

Strategy 6: Pre-Computed Error Resolution Scripts

For recurring errors, create fix scripts that Claude Code can execute directly instead of diagnosing:

#!/bin/bash
# scripts/fix-common-errors.sh
# Automated fixes for the 5 most common development errors
set -uo pipefail
ERROR_TYPE="${1:-help}"
case "$ERROR_TYPE" in
  "port-in-use")
    echo "Fixing: Port already in use"
    lsof -ti:3000 | xargs kill -9 2>/dev/null || true
    echo "FIXED: Port 3000 freed"
    ;;
  "prisma-drift")
    echo "Fixing: Prisma schema drift"
    npx prisma generate
    npx prisma db push --accept-data-loss 2>/dev/null || npx prisma migrate dev
    echo "FIXED: Schema synchronized"
    ;;
  "node-modules")
    echo "Fixing: Corrupted node_modules"
    rm -rf node_modules .next
    pnpm install
    echo "FIXED: Dependencies reinstalled"
    ;;
  *)
    echo "Available fixes: port-in-use, prisma-drift, node-modules"
    ;;
esac

Claude Code runs ./scripts/fix-common-errors.sh port-in-use in one tool call (~245 tokens) instead of diagnosing “address already in use” through 4-5 investigative calls (~2,000 tokens).

Savings: ~1,755 tokens per known error fix (88% reduction)

Measuring Your Savings

Track debugging efficiency using /cost output:

# Before structured errors:
# Debugging session for type error: 45,000 tokens, $0.13
# (8 tool calls: run, read, search, read, try-fix, run, read, fix)
# After structured errors:
# Debugging session for type error: 12,000 tokens, $0.04
# (3 tool calls: run, recognize, fix)

Cost Impact Summary

Technique Token Savings per Error Monthly Savings (Solo Dev)
JSON build output 1,600-3,600 $0.96-$2.16
Error catalog in CLAUDE.md 1,145 per known error $1.14-$3.44
Exit code contracts 2,000-5,000 $1.20-$3.00
Structured test output 3,000-8,000 $1.80-$4.80
Combined 8,000-18,000/session $5.10-$13.40

Monthly estimates: 20 working days, 5 debugging sessions/day, Sonnet 4.6 rates.

Measuring Error Handling ROI

Track the impact of structured error handling on debugging costs:

# Compare debugging sessions before and after implementing structured errors
# Before: average debugging session = 45,000 tokens
# After: average debugging session = 15,000 tokens
# Savings per debug session: 30,000 tokens ($0.18 on Sonnet 4.6)
# Average debugging sessions per day: 3
# Monthly savings: 3 x 20 x $0.18 = $10.80 per developer
# The investment to implement structured error handling:
# Exit code contracts: 30 minutes
# Error catalog in CLAUDE.md: 20 minutes
# JSON output wrappers: 1 hour
# Total investment: ~2 hours
# Payback: 4 working days

The structured error handling approach pays back within the first week and continues saving tokens indefinitely. It also makes the development experience better for humans – structured error output benefits both Claude Code and developers reading logs.

For teams, the savings multiply: 5 developers each saving $10.80/month = $54/month. The 2-hour implementation is a one-time cost shared across the team. The ongoing savings make structured error handling one of the highest-ROI optimizations available – it reduces both token costs and developer frustration simultaneously.

Estimate tokens → Calculate your usage with our Token Estimator.

Try it: Paste your error into our Error Diagnostic for an instant fix.