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

  1. Use only documented retry keys: `limit`, `methods`, `statusCodes`, `errorCodes`, `maxRetryAfter`, `noise`, `calculateDelay`, `enforceRetryRules`.
  2. For total retry count use `retry.limit` (not `retries`).
  3. 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

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


AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03). Data as JSON: /data/errors/31d35dae80e76f57.json. Report an issue: GitHub.