upstash/context7 · error · TypeError
retry.retries must be a non-negative integer
Error message
retry.retries must be a non-negative integer
What it means
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.
Source
Thrown at packages/sdk/src/http/retry.ts:8
import type { RetryConfig, RetryPolicy } from "./types";
export const DEFAULT_RETRY_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]);
export function createRetryPolicy(config?: RetryConfig): RetryPolicy {
const retries = config === false ? 0 : (config?.retries ?? 5);
if (!Number.isInteger(retries) || retries < 0) {
throw new TypeError("retry.retries must be a non-negative integer");
}
return {
retries,
backoff: config === false ? () => 0 : (config?.backoff ?? defaultBackoff),
statuses: new Set(config === false ? [] : (config?.statuses ?? DEFAULT_RETRY_STATUSES)),
};
}
export function isTransientStatus(status: number): boolean {
return DEFAULT_RETRY_STATUSES.has(status);
}
export function retryDelay(backoff: number, retryAfter?: number): number {
return Math.max(backoff, retryAfter === undefined ? 0 : retryAfter * 1000);
}
function defaultBackoff(retryCount: number): number {View on GitHub (pinned to 80e681a507)
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.
Example fix
// before
new Context7Client({ retry: { retries: Number(process.env.RETRIES) } }); // '' -> NaN -> TypeError
// after
const n = Math.floor(Number(process.env.RETRIES ?? 5));
new Context7Client({ retry: { retries: Number.isInteger(n) && n >= 0 ? n : 5 } }); Defensive patterns
Strategy: validation
Validate before calling
function assertRetries(n: unknown): asserts n is number {
if (!(Number.isInteger(n) && (n as number) >= 0)) {
throw new TypeError(`retry.retries must be a non-negative integer, got ${String(n)}`);
}
} Type guard
function isValidRetryCount(n: unknown): n is number {
return typeof n === 'number' && Number.isInteger(n) && n >= 0;
} Try / catch
try {
const client = new Context7Client({ retry: retryConfig });
} catch (e) {
if (e instanceof TypeError && /retry\.retries/.test(e.message)) {
console.error('Bad retry config; disabling retries');
}
throw e;
} Prevention
- 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)).
When it happens
Trigger: new Context7Client({ retry: { retries: -1 } }), retries: 2.5, retries: Infinity, or retry: { retries: '5' } (string) — anything failing Number.isInteger(retries) || retries < 0.
Common situations: 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.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Invalid MCP_MAX_SUBSCRIPTIONS; using the default of ${DEFAUL
- timeout must be a positive number or false
- invalid_url
- Unsafe skill name: ${JSON.stringify(skillName)}
- Skill name "${skillName}" escapes the skills root
AI-assisted analysis of upstash/context7@80e681a507 (2026-09-08).
Data as JSON: /api/errors/15a7f4cf1b9ad782.
Report an issue: GitHub.