{"id":"31d35dae80e76f57","repo":"sindresorhus/got","slug":"unexpected-retry-option-key","errorCode":null,"errorMessage":"Unexpected retry option: ${key}","messagePattern":"Unexpected retry option: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"source/core/options.ts","lineNumber":3082,"sourceCode":"\t\tassertAny('retry.maxRetryAfter', [is.number, is.undefined], value.maxRetryAfter);\n\t\tassertAny('retry.limit', [is.number, is.undefined], value.limit);\n\t\tassertAny('retry.methods', [is.array, is.undefined], value.methods);\n\t\tassertAny('retry.statusCodes', [is.array, is.undefined], value.statusCodes);\n\t\tassertAny('retry.errorCodes', [is.array, is.undefined], value.errorCodes);\n\t\tassertAny('retry.noise', [is.number, is.undefined], value.noise);\n\t\tassertAny('retry.enforceRetryRules', [is.boolean, is.undefined], value.enforceRetryRules);\n\n\t\tif (value.noise && Math.abs(value.noise) > 100) {\n\t\t\tthrow new Error(`The maximum acceptable retry noise is +/- 100ms, got ${value.noise}`);\n\t\t}\n\n\t\tfor (const key of Object.keys(value)) {\n\t\t\tif (key === '__proto__') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!(key in this.#internals.retry)) {\n\t\t\t\tthrow new Error(`Unexpected retry option: ${key}`);\n\t\t\t}\n\t\t}\n\n\t\tif (this.#merging) {\n\t\t\tsafeObjectAssign(this.#internals.retry, value);\n\t\t} else {\n\t\t\tthis.#internals.retry = {...value};\n\t\t}\n\n\t\tconst {retry} = this.#internals;\n\n\t\tretry.methods = [...new Set(retry.methods!.map(method => method.toUpperCase() as Method))];\n\t\tretry.statusCodes = [...new Set(retry.statusCodes)];\n\t\tretry.errorCodes = [...new Set(retry.errorCodes)];\n\t}\n\n\t/**\n\tFrom `http.RequestOptions`.","sourceCodeStart":3064,"sourceCodeEnd":3100,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/options.ts#L3064-L3100","documentation":"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.","triggerScenarios":"Calling `got(url, {retry: {retries: 5}})` (old Got name; now `limit`), `{retry: {retryDelay: ...}}`, or any retry key outside the documented set.","commonSituations":"Migrating from Got v11 (`retries`) or another library; typos; using a retry option from a different major version.","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."],"exampleFix":"// before\nawait got(url, {retry: {retries: 5}});\n// after\nawait got(url, {retry: {limit: 5}});","handlingStrategy":"type-guard","validationCode":"const validRetryKeys = new Set(['limit','methods','statusCodes','errorCodes','maxRetryAfter','noise','calculateDelay','enforceRetryRules']);\nfunction validateRetry(retry) {\n  for (const k of Object.keys(retry ?? {})) {\n    if (!validRetryKeys.has(k)) throw new Error(`Unknown retry option: ${k}`);\n  }\n}","typeGuard":"import type {RetryOptions} from 'got';\nfunction isRetryOptions(v: unknown): v is Partial<RetryOptions> {\n  if (typeof v !== 'object' || v === null) return false;\n  return Object.keys(v).every(k => ['limit','methods','statusCodes','errorCodes','maxRetryAfter','noise','calculateDelay','enforceRetryRules','__proto__'].includes(k));\n}","tryCatchPattern":null,"preventionTips":["Use `retry.limit` (current name), not `retries` (v11).","Rely on the `RetryOptions` type to catch typos at compile time."],"tags":["options","retry","validation","typo","config"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}