{"record":{"id":"8e4f920018bbd37f","repo":"affaan-m/ECC","slug":"nodes-must-explicitly-list-one-or-more-non-empty","errorCode":null,"errorMessage":"--nodes must explicitly list one or more non-empty nodes.","messagePattern":"--nodes must explicitly list one or more non-empty nodes\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/ito.js","lineNumber":120,"sourceCode":"  }\n  return value;\n}\n\nfunction validateNodeQualificationArgs(args, environment) {\n  if (environment.ITO_ENABLE_SIXTYTWO_LIVE !== \"1\") {\n    throw new Error(\n      \"Live node qualification requires ITO_ENABLE_SIXTYTWO_LIVE=1 before any process is started.\"\n    );\n  }\n  if (args.filter((value) => value === \"--live-sixtytwo\").length !== 1) {\n    throw new Error(\n      \"Live node qualification requires --live-sixtytwo exactly once before any process is started.\"\n    );\n  }\n  requiredOptionValue(args, \"--cluster\");\n  const nodes = requiredOptionValue(args, \"--nodes\");\n  if (!nodes.split(\",\").every((node) => node.trim().length > 0)) {\n    throw new Error(\"--nodes must explicitly list one or more non-empty nodes.\");\n  }\n  const configDirectory = requiredOptionValue(args, \"--config-dir\");\n  if (!path.isAbsolute(configDirectory)) {\n    throw new Error(\"--config-dir must be an existing absolute directory.\");\n  }\n  try {\n    const resolved = fs.realpathSync.native(configDirectory);\n    if (\n      !fs.statSync(resolved).isDirectory()\n      || !fs.statSync(path.join(resolved, \"sixtytwo.yaml\")).isFile()\n    ) {\n      throw new Error(\"invalid qualification configuration\");\n    }\n  } catch {\n    throw new Error(\n      \"--config-dir must exist and contain a regular sixtytwo.yaml before any process is started.\"\n    );\n  }","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/ito.js#L102-L138","documentation":"validateNodeQualificationArgs in scripts/ito.js validates the --nodes option for the `ecc ito evals` command. It throws this error when any comma-separated entry in --nodes is empty or whitespace-only, e.g. `--nodes a,,b` or a trailing comma. This guards node qualification from launching processes against an incomplete node list.","triggerScenarios":"Running `ecc ito evals --live-sixtytwo ... --cluster X --nodes \"a,,b\"`, `--nodes \"\"`, `--nodes \"a,\"`, or `--nodes \" a, , b\"` — any split(\"\\,\") element whose trim() is empty.","commonSituations":"Manually editing a long node list and leaving a trailing comma; templating a node list where a variable expands empty; copy-pasting lists with stray spaces between commas.","solutions":["Provide a comma-separated list where every entry is a non-empty trimmed node name, e.g. --nodes node-a,node-b","Strip trailing/leading commas and empty entries from the value before invoking the CLI","If nodes come from a template or variable, validate the joined string with a check like list.split(',').every(n => n.trim()) first"],"exampleFix":"// before\nrun(['--nodes', 'alpha,,beta'])\n// after\nrun(['--nodes', 'alpha,beta'])","handlingStrategy":"validation","validationCode":"function validateNodes(v) { return typeof v === 'string' && v.split(',').every(n => n.trim().length > 0); }\nif (!validateNodes(nodes)) throw new Error('every --nodes entry must be non-empty');","typeGuard":"const isNodeList = (v) => typeof v === 'string' && v.length > 0 && v.split(',').every((n) => n.trim().length > 0);","tryCatchPattern":"try {\n  runEccItoEvals(nodes);\n} catch (e) {\n  if (e.message.includes('--nodes')) {\n    const cleaned = nodes.split(',').map(s => s.trim()).filter(Boolean).join(',');\n    retryWith(cleaned);\n  } else throw e;\n}","preventionTips":["Normalize node lists (trim, drop empties) at the point where they are built","Never template node lists from variables without validating the joined string","Avoid hand-editing long comma lists; generate them programmatically"],"tags":["cli","validation","argument-format"],"backgroundTag":"invalid-argument-value","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}