{"record":{"id":"0a2be8c4884e9f46","repo":"paperclipai/paperclip","slug":"maxparallel-must-be-an-integer-from-2-through-100","errorCode":null,"errorMessage":"maxParallel must be an integer from 2 through 100","messagePattern":"maxParallel must be an integer from 2 through 100","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/scripts/runner-protocol-eval-campaign.mjs","lineNumber":126,"sourceCode":"    );\n  }\n  return new Set(selected);\n}\n\nexport async function buildProtocolEvalCatalog({\n  evalsRoot,\n  rosterSelection = \"all\",\n  campaignId,\n  source = {},\n  maxParallel = 100,\n}) {\n  safeId(campaignId, \"campaign ID\");\n  if (\n    !Number.isSafeInteger(maxParallel) ||\n    maxParallel < 2 ||\n    maxParallel > 100\n  ) {\n    throw new Error(\"maxParallel must be an integer from 2 through 100\");\n  }\n  const programRoot = resolve(evalsRoot, \"evals/paperclip-runner\");\n  const rosterRoot = resolve(programRoot, \"rosters\");\n  const requested = parseRosterSelection(rosterSelection);\n  const selected = requested ?? (await maintainedRosterSelection(programRoot));\n  const rosterFiles = (await readdir(rosterRoot, { withFileTypes: true }))\n    .filter(\n      (entry) =>\n        entry.isFile() &&\n        entry.name.startsWith(\"live-\") &&\n        entry.name.endsWith(\".json\"),\n    )\n    .map((entry) => entry.name)\n    .sort();\n  const rosters = [];\n  for (const rosterFile of rosterFiles) {\n    const rosterPath = resolve(rosterRoot, rosterFile);\n    const roster = await loadObject(rosterPath);","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/scripts/runner-protocol-eval-campaign.mjs#L108-L144","documentation":"buildProtocolEvalCatalog validates maxParallel as a safe integer between 2 and 100 inclusive before building the eval catalog. Values outside that range, non-integers, or non-numeric input are rejected. This bounds live eval concurrency to a sane, safe range.","triggerScenarios":"Calling buildProtocolEvalCatalog with maxParallel = 1, 0, negative, > 100, a float like 2.5, or undefined/NaN (e.g. from an unparsed CLI flag).","commonSituations":"Passing --max-parallel 1 wanting serial execution; forgetting to Number() a string CLI arg so '8' arrives as a string; typo resulting in NaN; setting a very high value hoping to speed up the run.","solutions":["Pass an integer between 2 and 100, e.g. 8.","Coerce the CLI value with Number() and validate before calling (Number.isSafeInteger + range check).","For serial execution, check whether the script offers a dedicated serial/sequence mode instead of maxParallel: 1."],"exampleFix":"// before\nconst maxParallel = args[\"max-parallel\"]; // \"1\" (string)\n// after\nconst maxParallel = Number(args[\"max-parallel\"] ?? 8);\nif (!Number.isSafeInteger(maxParallel) || maxParallel < 2 || maxParallel > 100) throw new Error(\"maxParallel must be an integer from 2 through 100\");","handlingStrategy":"validation","validationCode":"const maxParallel = Number(rawMaxParallel);\nif (!Number.isSafeInteger(maxParallel) || maxParallel < 2 || maxParallel > 100) throw new Error(\"maxParallel must be an integer from 2 through 100\");","typeGuard":"const isValidMaxParallel = (v) => Number.isSafeInteger(v) && v >= 2 && v <= 100;","tryCatchPattern":"try {\n  const catalog = await buildProtocolEvalCatalog({ maxParallel });\n} catch (err) {\n  if (err.message.includes(\"maxParallel\")) console.error(\"Pass an integer 2-100, e.g. --max-parallel 8\");\n  throw err;\n}","preventionTips":["Coerce and validate CLI numeric flags with Number()/Number.isSafeInteger before use.","Default maxParallel to a known-good value (e.g. 8) when the flag is absent.","Clamp parsed values: Math.min(100, Math.max(2, Math.round(n)))."],"tags":["validation","concurrency","cli"],"backgroundTag":"value-out-of-range","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}