vercel/ai · error · MCPClientError

maxRetries must be >= 0

Error message

maxRetries must be >= 0

What it means

Thrown by prepareMaxRetries when maxRetries is a negative integer. Retrying a negative number of times is meaningless, so the constructor rejects it with MCPClientError.

Source

Thrown at packages/mcp/src/tool/mcp-client.ts:151

  }

  const errorCode = getStringErrorCode(error);
  return errorCode != null && DEFAULT_RETRY_ERROR_CODES.includes(errorCode);
}

function prepareMaxRetries(maxRetries: number | undefined): number {
  if (maxRetries == null) {
    return DEFAULT_MAX_TOOL_CALL_RETRIES;
  }

  if (!Number.isInteger(maxRetries)) {
    throw new MCPClientError({
      message: 'maxRetries must be an integer',
    });
  }

  if (maxRetries < 0) {
    throw new MCPClientError({
      message: 'maxRetries must be >= 0',
    });
  }

  return maxRetries;
}

function getEffectiveTimeout({
  timeout,
  maxTotalTimeout,
}: RequestOptions): number | undefined {
  if (timeout == null) {
    return maxTotalTimeout;
  }

  if (maxTotalTimeout == null) {
    return timeout;
  }

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Use 0 to disable retries instead of a negative number.
  2. Clamp with Math.max(0, value) before constructing the client.
  3. Fix the source config/env value.

Example fix

// before
new MCPClient({ ..., maxRetries: -1 });
// after
new MCPClient({ ..., maxRetries: Math.max(0, Number(process.env.MCP_RETRIES ?? 2)) });
Defensive patterns

Strategy: validation

Validate before calling

const maxRetries = Math.max(0, Number.parseInt(process.env.MCP_RETRIES ?? '2', 10));
if (!Number.isInteger(maxRetries) || maxRetries < 0) {
  throw new Error('maxRetries must be a non-negative integer');
}

Type guard

function isNonNegativeInt(v: unknown): v is number {
  return typeof v === 'number' && Number.isInteger(v) && v >= 0;
}

Try / catch

try {
  const client = await createMCPClient({ transport, maxRetries });
} catch (e) {
  if (MCPClientError.isInstance(e) && e.message === 'maxRetries must be >= 0') {
    // clamp and retry construction
  } else throw e;
}

Prevention

When it happens

Trigger: new MCPClient({ maxRetries: -1 }) or any negative integer, typically from miscomputed config (e.g. subtracting counts) or a sentinel value.

Common situations: Env-derived values like MAX_RETRIES=-1 used to mean 'disable retries'; arithmetic mistakes in derived config; misunderstanding that 0 is the correct way to disable retries.

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 vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/08e082aa665991b2. Report an issue: GitHub.