n8n-io/n8n · error · Error

--max-attempts must be >= 1

Error message

--max-attempts must be >= 1

What it means

Thrown by the build-mcp-manifest CLI after argument parsing. The --max-attempts flag controls how many total build attempts the builder makes per slug when a workflow ID is missing from the model's output. The check `result.maxAttempts < 1` rejects zero or negative values because zero attempts would mean no build work is done at all, making the entire run meaningless.

Source

Thrown at packages/@n8n/instance-ai/evaluations/cli/build-mcp-manifest.ts:232

				result.suite = nextArg(argv, i, arg);
				i += 2;
				break;
			case '-h':
			case '--help':
				return { helpRequested: true };
			default:
				if (arg.startsWith('--')) {
					throw new Error(`Unknown flag: ${arg.split('=', 1)[0]} (use --help)`);
				}
				result.slugs.push(arg);
				i += 1;
				break;
		}
	}

	if (result.iterations < 1) throw new Error('--iterations must be >= 1');
	if (result.concurrency < 1) throw new Error('--concurrency must be >= 1');
	if (result.maxAttempts < 1) throw new Error('--max-attempts must be >= 1');
	if (result.source === 'langtracer' && !result.suite) {
		throw new Error('--source langtracer requires --suite <slug>');
	}

	mkdirSync(result.outputDir, { recursive: true });
	if (!result.manifestPath) result.manifestPath = join(result.outputDir, 'manifest.json');
	if (!result.logDir) result.logDir = join(result.outputDir, 'logs');
	const base = result.manifestPath.replace(/\.json$/, '');
	result.statsPath = `${base}-stats.json`;
	mkdirSync(result.logDir, { recursive: true });

	return { helpRequested: false, args: result };
}

function readJson(path: string, label: string): unknown {
	const content = readFileSync(path, 'utf-8');
	try {
		return JSON.parse(content);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Set --max-attempts to 1 or higher (the default is 3)
  2. Remove the flag entirely to use the default of 3
  3. If you want exactly one attempt with no retries, use --max-attempts 1

Example fix

# before
pnpm eval:build-mcp-manifest --max-attempts 0

# after
pnpm eval:build-mcp-manifest --max-attempts 1
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking the CLI, validate numeric args in your wrapper script:
const rawMaxAttempts = process.env.MAX_ATTEMPTS ?? '3';
const maxAttempts = Number.parseInt(rawMaxAttempts, 10);
if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
  throw new Error(`--max-attempts must be an integer >= 1, got: ${rawMaxAttempts}`);
}

Type guard

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

Prevention

When it happens

Trigger: Running `pnpm eval:build-mcp-manifest --max-attempts 0` or `--max-attempts -1`. The value passes parseIntArg (0 and -1 are valid integers) but fails this post-parse range check at line 232.

Common situations: Developer sets --max-attempts to 0 thinking it means 'one attempt, no retries', not realizing the flag counts total attempts. A scripted/automated invocation passes 0 by default. A negative value from a misconfigured variable.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/111d1eb5cfd6f6d1. Report an issue: GitHub.