Skip to content
CI/CD & Automation Intermediate

Retry with Backoff

Handle transient API failures (network errors, timeouts, 500s) with exponential retry logic

Command

$ retry_claude() {
    local max=3 prompt="$1"; shift
    "color:#7C5CFC">for attempt in $(seq 1 "$max"); "color:#7C5CFC">do
      "color:#7C5CFC">if RESULT=$("color:#7C5CFC">claude -p "$prompt" "$@" 2>/dev/null); "color:#7C5CFC">then
        "color:#7C5CFC">if "color:#7C5CFC">echo "$RESULT" | "color:#7C5CFC">jq -e '.is_error != true' >/dev/null 2>&1; "color:#7C5CFC">then
          "color:#7C5CFC">echo "$RESULT"; return 0
        "color:#7C5CFC">fi
      "color:#7C5CFC">fi
      "color:#7C5CFC">echo "Attempt $attempt/$max failed" >&2
      sleep "$((attempt * 5))"
    "color:#7C5CFC">done
    return 1
  }

Response

Attempt 1/3 failed, retrying in 5s...
Attempt 2/3 succeeded.
{
  "subtype": "success",
  "result": "..."
}

Parsing Code

059669">">async 059669">">function retryClaudeJS(prompt, opts, maxRetries = 3) {
  059669">">for (059669">">let i = 1; i <= maxRetries; i++) {
    059669">">try {
      059669">">const data = JSON.parse(execFileSync(059669059669">">'claude', [
        059669059669">">'-p', prompt, 059669059669">">'--output-format', 059669059669">">'json', ...opts
      ], { encoding: 059669059669">">'utf-8', timeout: 120_000, env: { ...process.env, CLAUDECODE: 059669059669">">'' } }));
      059669">">if (!data.is_error) 059669">">return data;
    } 059669">">catch (err) { /* retry */ }
    059669">">await 059669">">new Promise(r => setTimeout(r, i * 5000));
  }
  059669">">throw 059669">">new Error(059669">'All retries failed');
}

Gotchas

! --fallback-model only handles HTTP 429 rate limits, NOT network errors or 500s
! Always check is_error field to distinguish controlled stops from actual failures

Related Recipes