{"record":{"id":"15a7f4cf1b9ad782","repo":"upstash/context7","slug":"retry-retries-must-be-a-non-negative-integer","errorCode":null,"errorMessage":"retry.retries must be a non-negative integer","messagePattern":"retry\\.retries must be a non-negative integer","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/sdk/src/http/retry.ts","lineNumber":8,"sourceCode":"import type { RetryConfig, RetryPolicy } from \"./types\";\n\nexport const DEFAULT_RETRY_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]);\n\nexport function createRetryPolicy(config?: RetryConfig): RetryPolicy {\n  const retries = config === false ? 0 : (config?.retries ?? 5);\n  if (!Number.isInteger(retries) || retries < 0) {\n    throw new TypeError(\"retry.retries must be a non-negative integer\");\n  }\n\n  return {\n    retries,\n    backoff: config === false ? () => 0 : (config?.backoff ?? defaultBackoff),\n    statuses: new Set(config === false ? [] : (config?.statuses ?? DEFAULT_RETRY_STATUSES)),\n  };\n}\n\nexport function isTransientStatus(status: number): boolean {\n  return DEFAULT_RETRY_STATUSES.has(status);\n}\n\nexport function retryDelay(backoff: number, retryAfter?: number): number {\n  return Math.max(backoff, retryAfter === undefined ? 0 : retryAfter * 1000);\n}\n\nfunction defaultBackoff(retryCount: number): number {","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/upstash/context7/blob/80e681a507c5287bc12e483367c40754e29461b9/packages/sdk/src/http/retry.ts#L1-L26","documentation":"A TypeError raised at the top of createRetryPolicy when the retries option supplied in RetryConfig is not a whole number >= 0 (e.g. 2.5, -1, NaN, or a non-numeric value). It is a generic input-validation guard, not a network failure: the caller passed an invalid retry count, so no retry policy can be constructed. Valid values are non-negative integers; the default is 5 when config or config.retries is omitted, and config === false bypasses this check with retries = 0.","triggerScenarios":"new Context7Client({ retry: { retries: -1 } }), retries: 2.5, retries: Infinity, or retry: { retries: '5' } (string) — anything failing Number.isInteger(retries) || retries < 0.","commonSituations":"Parsing retries from env/config without Number coercion, computing retries from a formula yielding a float, or using -1 intending 'unlimited'/'disabled' instead of retry: false.","solutions":["Pass a non-negative integer, e.g. retry: { retries: 5 } (default).","To disable retries, pass retry: false rather than retries: 0 intent via negative numbers.","Coerce config values: const n = Math.floor(Number(raw)); check Number.isInteger(n) && n >= 0 before passing.","Review any derived retry counts (e.g. based on env) for NaN/Infinity."],"exampleFix":"// before\nnew Context7Client({ retry: { retries: Number(process.env.RETRIES) } }); // '' -> NaN -> TypeError\n// after\nconst n = Math.floor(Number(process.env.RETRIES ?? 5));\nnew Context7Client({ retry: { retries: Number.isInteger(n) && n >= 0 ? n : 5 } });","handlingStrategy":"validation","validationCode":"function assertRetries(n: unknown): asserts n is number {\n  if (!(Number.isInteger(n) && (n as number) >= 0)) {\n    throw new TypeError(`retry.retries must be a non-negative integer, got ${String(n)}`);\n  }\n}","typeGuard":"function isValidRetryCount(n: unknown): n is number {\n  return typeof n === 'number' && Number.isInteger(n) && n >= 0;\n}","tryCatchPattern":"try {\n  const client = new Context7Client({ retry: retryConfig });\n} catch (e) {\n  if (e instanceof TypeError && /retry\\.retries/.test(e.message)) {\n    console.error('Bad retry config; disabling retries');\n  }\n  throw e;\n}","preventionTips":["Coerce config with Math.floor(Number(v)) and validate >= 0.","Use retry: false to disable retries, never a negative count.","Schema-validate retry config at startup (zod: z.number().int().min(0))."],"tags":["configuration","validation","retry"],"backgroundTag":"invalid-config-value","analyzedSha":"80e681a507c5287bc12e483367c40754e29461b9","analyzedAt":"2026-09-08T05:18:41.043Z","contentChangedAt":"2026-09-08T05:18:41.043Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}