{"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":null,"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/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/ito.js#L102-L138","documentation":"The --nodes value is a comma-separated list, and every entry must be non-empty after trimming. The validator splits on ',' and checks each element; an empty element (a leading/trailing comma or a double comma) is rejected so that no blank node slips through to live qualification.","triggerScenarios":"Passing --nodes n1,,n2 (double comma), --nodes ,n1 (leading comma), --nodes n1, (trailing comma), or --nodes ',' (only separators).","commonSituations":"Building the node list dynamically and joining with a comma when one source is empty, or a copy-paste that leaves a stray comma.","solutions":["List each node explicitly with no empty entries, e.g. --nodes n1,n2,n3","Filter empty values when constructing the list dynamically before passing it to --nodes","Validate the list with a quick check: echo \"$LIST\" | tr ',' '\\n' | grep -q '^ *$' && echo empty-entry"],"exampleFix":"// before\n--nodes n1,,n2\n// after\n--nodes n1,n2","handlingStrategy":"validation","validationCode":"function assertNodesList(nodes) {\n  const parts = String(nodes).split(',');\n  if (parts.length === 0 || !parts.every(n => n.trim().length > 0)) {\n    throw new Error('--nodes contains an empty entry');\n  }\n}\nconst i = args.indexOf('--nodes');\nif (i !== -1) assertNodesList(args[i + 1]);","typeGuard":"function isDenseNodeList(nodes) {\n  if (typeof nodes !== 'string') return false;\n  const parts = nodes.split(',');\n  return parts.length > 0 && parts.every(n => n.trim().length > 0);\n}","tryCatchPattern":"try { validateNodeQualificationArgs(args, env); }\ncatch (err) {\n  if (/--nodes must explicitly list/.test(err.message)) {\n    console.error(err.message);\n    process.exit(2);\n  }\n  throw err;\n}","preventionTips":["Build node lists by filtering empties before joining with commas","Avoid leading, trailing, and double commas in --nodes values","Unit-test dynamic list construction against the dense-list guard"],"tags":["cli","argument-validation","ito","live-qualification"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}