{"record":{"id":"111d1eb5cfd6f6d1","repo":"n8n-io/n8n","slug":"max-attempts-must-be-1","errorCode":null,"errorMessage":"--max-attempts must be >= 1","messagePattern":"--max-attempts must be >= 1","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/instance-ai/evaluations/cli/build-mcp-manifest.ts","lineNumber":232,"sourceCode":"\t\t\t\tresult.suite = nextArg(argv, i, arg);\n\t\t\t\ti += 2;\n\t\t\t\tbreak;\n\t\t\tcase '-h':\n\t\t\tcase '--help':\n\t\t\t\treturn { helpRequested: true };\n\t\t\tdefault:\n\t\t\t\tif (arg.startsWith('--')) {\n\t\t\t\t\tthrow new Error(`Unknown flag: ${arg.split('=', 1)[0]} (use --help)`);\n\t\t\t\t}\n\t\t\t\tresult.slugs.push(arg);\n\t\t\t\ti += 1;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (result.iterations < 1) throw new Error('--iterations must be >= 1');\n\tif (result.concurrency < 1) throw new Error('--concurrency must be >= 1');\n\tif (result.maxAttempts < 1) throw new Error('--max-attempts must be >= 1');\n\tif (result.source === 'langtracer' && !result.suite) {\n\t\tthrow new Error('--source langtracer requires --suite <slug>');\n\t}\n\n\tmkdirSync(result.outputDir, { recursive: true });\n\tif (!result.manifestPath) result.manifestPath = join(result.outputDir, 'manifest.json');\n\tif (!result.logDir) result.logDir = join(result.outputDir, 'logs');\n\tconst base = result.manifestPath.replace(/\\.json$/, '');\n\tresult.statsPath = `${base}-stats.json`;\n\tmkdirSync(result.logDir, { recursive: true });\n\n\treturn { helpRequested: false, args: result };\n}\n\nfunction readJson(path: string, label: string): unknown {\n\tconst content = readFileSync(path, 'utf-8');\n\ttry {\n\t\treturn JSON.parse(content);","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/instance-ai/evaluations/cli/build-mcp-manifest.ts#L214-L250","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set --max-attempts to 1 or higher (the default is 3)","Remove the flag entirely to use the default of 3","If you want exactly one attempt with no retries, use --max-attempts 1"],"exampleFix":"# before\npnpm eval:build-mcp-manifest --max-attempts 0\n\n# after\npnpm eval:build-mcp-manifest --max-attempts 1","handlingStrategy":"validation","validationCode":"// Before invoking the CLI, validate numeric args in your wrapper script:\nconst rawMaxAttempts = process.env.MAX_ATTEMPTS ?? '3';\nconst maxAttempts = Number.parseInt(rawMaxAttempts, 10);\nif (!Number.isInteger(maxAttempts) || maxAttempts < 1) {\n  throw new Error(`--max-attempts must be an integer >= 1, got: ${rawMaxAttempts}`);\n}","typeGuard":"function isValidAttemptCount(v: unknown): v is number {\n  return typeof v === 'number' && Number.isInteger(v) && v >= 1;\n}","tryCatchPattern":null,"preventionTips":["Use the default (3) unless you have a specific reason to change maxAttempts","Validate integer CLI args in wrapper scripts before passing them through"],"tags":["cli","validation","argument-parsing","build-mcp-manifest"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}