dubinc/dub · error
Failed after ${maxRetries} retries. Last error: ${lastError.
Error message
Failed after ${maxRetries} retries. Last error: ${lastError.message} What it means
fetchWithRetry throws this Error when every one of the maxRetries attempts fails with a retryable condition — network failure, DNS error, abort due to timeout, or repeated 429/5xx responses. The original cause is preserved in the message as `Last error: ...`, so the final thrown error is a wrapper describing exhausted retries plus the last underlying failure.
Source
Thrown at packages/utils/src/functions/fetch-with-retry.ts:64
let errorMessage: string;
try {
const error = await response.json();
errorMessage = error.error || `HTTP error ${response.status}`;
} catch {
errorMessage = `HTTP error ${response.status}`;
}
console.error(`fetchWithRetry error: ${errorMessage}`);
throw new Error(errorMessage);
}
} catch (error) {
clearTimeout(timeoutId);
lastError = error instanceof Error ? error : new Error(String(error));
// If this is the last retry, throw the error
if (i === maxRetries - 1) {
const errMsg = `Failed after ${maxRetries} retries. Last error: ${lastError.message}`;
console.error(`fetchWithRetry error: ${errMsg}`);
throw new Error(errMsg);
}
// For network errors or timeouts, wait and retry
const delay = retryDelay + Math.pow(i, 2) * 50;
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
// This should never be reached due to the throw in the last retry,
// but TypeScript needs it for type safety
throw new Error(`Failed after ${maxRetries} retries`);
}
View on GitHub (pinned to f216b94a24)
Solutions
- Read the `Last error:` suffix to identify the root cause (AbortError/timeout vs TypeError/network vs 429/5xx).
- If timeouts dominate, raise the `timeout` option (e.g. timeout: 30000) so slow endpoints aren't aborted.
- If 429/5xx dominate, increase `maxRetries` and `retryDelay`, or back off globally — the server may need minutes, not seconds.
- Check basic connectivity to the host (curl/ping) and any proxy/firewall settings before re-running.
- Wrap the call in your own try/catch and fall back to cached data or queue the work for later retry.
Example fix
// before
const res = await fetchWithRetry(url); // default 5s timeout exhausts retries
// after
const res = await fetchWithRetry(url, undefined, { timeout: 30000, maxRetries: 5, retryDelay: 2000 }); Defensive patterns
Strategy: retry
Validate before calling
// Check reachability before the call
const host = new URL(input instanceof URL ? input.href : String(input)).host;
const reachable = await fetch(`https://${host}/`, { method: 'HEAD' }).then(r => r.ok).catch(() => false);
if (!reachable) console.warn('Host unreachable; expect retries to exhaust'); Type guard
function isRetryExhaustionError(e: unknown): e is Error {
return e instanceof Error && /^Failed after \d+ retries\./.test(e.message);
} Try / catch
try {
const res = await fetchWithRetry(url, init, { timeout: 30000, maxRetries: 5, retryDelay: 2000 });
} catch (e) {
if (isRetryExhaustionError(e)) {
// queue for later / serve cached data / alert on the underlying cause
} else {
throw e;
}
} Prevention
- Tune timeout/maxRetries/retryDelay for slow or rate-limited endpoints.
- Parse the `Last error:` suffix to distinguish timeouts from network failures from 429/5xx.
- For sustained rate limits, add client-side throttling instead of burning retries.
- Monitor the endpoint's health rather than relying on retries during outages.
When it happens
Trigger: maxRetries consecutive attempts where fetch rejects (offline/DNS failure), the AbortController fires (response slower than `timeout`, default 5000ms), or the server keeps returning 429 or 5xx on every attempt.
Common situations: Calling an API that is down or deploying during an outage, running behind a firewall/VPN blocking the host, a slow endpoint exceeding the 5s default timeout 10 times in a row, or sustained rate limiting (429) that outlasts the backoff schedule.
Related errors
AI-assisted analysis of dubinc/dub@f216b94a24 (2026-08-31).
Data as JSON: /api/errors/8ab4743bb2740a44.
Report an issue: GitHub.