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

  1. Pass a non-negative integer, e.g. retry: { retries: 5 } (default).
  2. To disable retries, pass retry: false rather than retries: 0 intent via negative numbers.
  3. Coerce config values: const n = Math.floor(Number(raw)); check Number.isInteger(n) && n >= 0 before passing.
  4. 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

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


AI-assisted analysis of upstash/context7@80e681a507 (2026-09-08). Data as JSON: /api/errors/15a7f4cf1b9ad782. Report an issue: GitHub.