ErrorCauseRecovery429 Rate LimitToo many requestsWait + retry with backoff402 BillingAPI credits exhaustedSwitch model or wait503 OverloadedProvider busyWait + retryContext OverflowContext window fullTrigger compactionRole OrderingCorrupted sessionReset sessionTransient HTTPNetwork issueAuto-retry (built-in)
javascript
async function retryWithBackoff(fn, maxAttempts = 3) {
for (let i = 0; i < maxAttempts; i++) {
try {
return await fn();
} catch (err) {
if (isRetryable(err) && i < maxAttempts - 1) {
await sleep(1000 * Math.pow(2, i)); // 1s, 2s, 4s
continue;
}
throw err;
}
}
}
javascript
async function withFallback(primary, fallback) {
try {
return await primary();
} catch (err) {
console.warn("Primary failed, trying fallback:", err.message);
return await fallback();
}
}
// Usage
const result = await withFallback(
() => callExpensiveModel(msg),
() => callCheapModel(msg)
);
javascript
class CircuitBreaker {
constructor(fn, threshold = 3) {
this.fn = fn;
this.failures = 0;
this.threshold = threshold;
this.state = "closed"; // open/closed/half-open
}
async execute() {
if (this.state === "open") {
throw new Error("Circuit breaker open");
}
try {
const result = await this.fn();
this.failures = 0;
this.state = "closed";
return result;
} catch (err) {
this.failures++;
if (this.failures >= this.threshold) {
this.state = "open";
}
throw err;
}
}
}
Tools in OpenClaw are non-fatal — if a tool fails, the agent continues:
javascript
// In agent-runner, tool errors are caught but don't stop execution
.catch((err) => {
log(`Tool ${toolName} failed: ${err.message}`);
// Continue execution
});
If session becomes corrupted:
MechanismTriggerActionAuto-retry408/429/5xxExponential backoffContext overflowToken limitTrigger compactionSession corruptionRole errorReset sessionModel switchpersistent failureFallback model