eyaltoledano/claude-task-master · error · TypeError

Invalid maxAttempts value: ${maxAttempts}. Must be a positiv

Error message

Invalid maxAttempts value: ${maxAttempts}. Must be a positive integer.

What it means

A synchronous TypeError guard in verifyMFAWithRetry. The method retries MFA verification a bounded number of times, so maxAttempts must be a finite positive integer (>= 1). Values like 0, -1, NaN, Infinity, or non-integers are rejected before any verification attempt is made.

Source

Thrown at packages/tm-core/src/modules/auth/managers/auth-manager.ts:174

	 */
	async verifyMFAWithRetry(
		factorId: string,
		codeProvider: () => Promise<string>,
		options?: {
			maxAttempts?: number;
			onInvalidCode?: (attempt: number, remaining: number) => void;
		}
	): Promise<MFAVerificationResult> {
		const maxAttempts = options?.maxAttempts ?? 3;
		const onInvalidCode = options?.onInvalidCode;

		// Guard against invalid maxAttempts values
		if (
			!Number.isFinite(maxAttempts) ||
			!Number.isInteger(maxAttempts) ||
			maxAttempts < 1
		) {
			throw new TypeError(
				`Invalid maxAttempts value: ${maxAttempts}. Must be a positive integer.`
			);
		}

		for (let attempt = 1; attempt <= maxAttempts; attempt++) {
			try {
				const code = await codeProvider();
				const credentials = await this.verifyMFA(factorId, code);
				return {
					success: true,
					attemptsUsed: attempt,
					credentials
				};
			} catch (error) {
				// Only retry on invalid MFA code errors
				if (
					error instanceof AuthenticationError &&
					error.code === 'INVALID_MFA_CODE'

View on GitHub (pinned to c0c98d367c)

Solutions

  1. Pass a positive integer, e.g. Math.max(1, Math.floor(Number(maxAttempts)))
  2. Validate user/config input before calling: Number.isInteger(n) && n >= 1
  3. If 0 was intended as 'single attempt, no retries', pass 1 instead

Example fix

// before
await auth.verifyMFAWithRetry(code, factorId, Number(opts.retries)); // NaN if flag missing
// after
const retries = Number(opts.retries ?? 1);
if (!Number.isInteger(retries) || retries < 1) throw new Error('retries must be a positive integer');
await auth.verifyMFAWithRetry(code, factorId, retries);
Defensive patterns

Strategy: validation

Validate before calling

function isValidMaxAttempts(n: unknown): n is number {
  return typeof n === 'number' && Number.isFinite(n) && Number.isInteger(n) && n >= 1;
}
if (!isValidMaxAttempts(maxAttempts)) maxAttempts = 1;

Type guard

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

Try / catch

try {
  await auth.verifyMFAWithRetry(code, factorId, maxAttempts);
} catch (e) {
  if (e instanceof TypeError && e.message.includes('maxAttempts')) {
    // programmer error: clamp and retry once with a valid value
    await auth.verifyMFAWithRetry(code, factorId, 3);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling authManager.verifyMFAWithRetry(code, factorId, maxAttempts) with maxAttempts = 0, a negative number, NaN, Infinity, or a fractional value like 1.5 — typically from unvalidated CLI input or a bad config value.

Common situations: CLI parsing that yields NaN when a flag is omitted; config files where attempts is a string like '3'; off-by-one logic passing 0 to mean 'no retries' (author intent) but failing validation.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29). Data as JSON: /api/errors/00606bd520993923. Report an issue: GitHub.