sindresorhus/got · error · Error
Unexpected retry option: ${key}
Error message
Unexpected retry option: ${key} What it means
Thrown by the `retry` setter when the `retry` object has a key that is not a recognized retry option. Valid keys are `limit`, `methods`, `statusCodes`, `errorCodes`, `maxRetryAfter`, `noise`, `calculateDelay`, `enforceRetryRules`. Unknown keys are rejected so typos do not silently disable a retry setting.
Source
Thrown at source/core/options.ts:3082
assertAny('retry.maxRetryAfter', [is.number, is.undefined], value.maxRetryAfter);
assertAny('retry.limit', [is.number, is.undefined], value.limit);
assertAny('retry.methods', [is.array, is.undefined], value.methods);
assertAny('retry.statusCodes', [is.array, is.undefined], value.statusCodes);
assertAny('retry.errorCodes', [is.array, is.undefined], value.errorCodes);
assertAny('retry.noise', [is.number, is.undefined], value.noise);
assertAny('retry.enforceRetryRules', [is.boolean, is.undefined], value.enforceRetryRules);
if (value.noise && Math.abs(value.noise) > 100) {
throw new Error(`The maximum acceptable retry noise is +/- 100ms, got ${value.noise}`);
}
for (const key of Object.keys(value)) {
if (key === '__proto__') {
continue;
}
if (!(key in this.#internals.retry)) {
throw new Error(`Unexpected retry option: ${key}`);
}
}
if (this.#merging) {
safeObjectAssign(this.#internals.retry, value);
} else {
this.#internals.retry = {...value};
}
const {retry} = this.#internals;
retry.methods = [...new Set(retry.methods!.map(method => method.toUpperCase() as Method))];
retry.statusCodes = [...new Set(retry.statusCodes)];
retry.errorCodes = [...new Set(retry.errorCodes)];
}
/**
From `http.RequestOptions`.View on GitHub (pinned to e3924aa1e5)
Solutions
- Use only documented retry keys: `limit`, `methods`, `statusCodes`, `errorCodes`, `maxRetryAfter`, `noise`, `calculateDelay`, `enforceRetryRules`.
- For total retry count use `retry.limit` (not `retries`).
- Check the `${key}` in the message and rename/remove it.
Example fix
// before
await got(url, {retry: {retries: 5}});
// after
await got(url, {retry: {limit: 5}}); Defensive patterns
Strategy: type-guard
Validate before calling
const validRetryKeys = new Set(['limit','methods','statusCodes','errorCodes','maxRetryAfter','noise','calculateDelay','enforceRetryRules']);
function validateRetry(retry) {
for (const k of Object.keys(retry ?? {})) {
if (!validRetryKeys.has(k)) throw new Error(`Unknown retry option: ${k}`);
}
} Type guard
import type {RetryOptions} from 'got';
function isRetryOptions(v: unknown): v is Partial<RetryOptions> {
if (typeof v !== 'object' || v === null) return false;
return Object.keys(v).every(k => ['limit','methods','statusCodes','errorCodes','maxRetryAfter','noise','calculateDelay','enforceRetryRules','__proto__'].includes(k));
} Prevention
- Use `retry.limit` (current name), not `retries` (v11).
- Rely on the `RetryOptions` type to catch typos at compile time.
When it happens
Trigger: Calling `got(url, {retry: {retries: 5}})` (old Got name; now `limit`), `{retry: {retryDelay: ...}}`, or any retry key outside the documented set.
Common situations: Migrating from Got v11 (`retries`) or another library; typos; using a retry option from a different major version.
Related errors
- Unexpected option: ${key}
- Unexpected hook event: ${knownHookEvent}
- The maximum acceptable retry noise is +/- 100ms, got ${value
- Unexpected agent option: ${key}
- Unexpected timeout option: ${key}
AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03).
Data as JSON: /data/errors/31d35dae80e76f57.json.
Report an issue: GitHub.