{"record":{"id":"2040e1cf5c61285a","repo":"affaan-m/ECC","slug":"invalid-qualification-configuration","errorCode":null,"errorMessage":"invalid qualification configuration","messagePattern":"invalid qualification configuration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/ito.js","lineNumber":132,"sourceCode":"      \"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  }\n}\n\nfunction parseArgs(argv, environment = process.env) {\n  const args = [...argv];\n  if (\n    args.length === 0\n    || args.includes(\"--help\")\n    || args.includes(\"-h\")\n  ) {\n    return Object.freeze({ help: true, invocationArgs: [] });\n  }\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/ito.js#L114-L150","documentation":"Thrown at scripts/ito.js:132 inside the try block of validateNodeQualificationArgs when the resolved config directory exists but is not a directory, OR when sixtytwo.yaml inside it is not a regular file. IMPORTANT: this throw is effectively UNREACHABLE as a user-facing message — it is thrown inside a try{} whose catch{} (ito.js:134-138) has no parameter and unconditionally re-throws error 102's message instead. Any user who triggers the condition at line 128-131 will actually see the error-102 text. This is a latent bug: the discriminating message at line 132 is dead code.","triggerScenarios":"The code path requires --config-dir to resolve (realpath succeeds), then either `fs.statSync(resolved).isDirectory()` is false (config-dir is a file/symlink-to-file/device) OR `fs.statSync(path.join(resolved, 'sixtytwo.yaml')).isFile()` is false (missing file, or sixtytwo.yaml is a directory/symlink). When triggered, the catch at ito.js:134 swallows this error and throws '--config-dir must exist and contain a regular sixtytwo.yaml before any process is started.'","commonSituations":"Operator points --config-dir at a regular file rather than a directory; or sixtytwo.yaml exists but is a directory (e.g. created via `mkdir sixtytwo.yaml`). In both cases the user sees error 102's message, not this one. Anyone reading the source will see this string but it never surfaces.","solutions":["Treat any '--config-dir must exist and contain a regular sixtytwo.yaml' report (error 102) as the actionable message — that is what you will actually see.","Ensure --config-dir is a directory containing a regular sixtytwo.yaml file (not a symlink-to-dir, not a file, not a missing file).","File an issue / fix the dead throw at ito.js:132: either give the catch a parameter and re-throw only on genuine fs errors, or rethrow this inner error verbatim so the discriminating message surfaces."],"exampleFix":"// before (scripts/ito.js:126-138) — inner message is masked\n  try {\n    const resolved = fs.realpathSync.native(configDirectory);\n    if (!fs.statSync(resolved).isDirectory()\n        || !fs.statSync(path.join(resolved, 'sixtytwo.yaml')).isFile()) {\n      throw new Error('invalid qualification configuration');\n    }\n  } catch {\n    throw new Error('--config-dir must exist and contain a regular sixtytwo.yaml ...');\n  }\n// after — only re-wrap genuine fs errors, let the validation message through\n  let resolved;\n  try {\n    resolved = fs.realpathSync.native(configDirectory);\n  } catch {\n    throw new Error('--config-dir must exist and contain a regular sixtytwo.yaml ...');\n  }\n  if (!fs.statSync(resolved).isDirectory()\n      || !fs.statSync(path.join(resolved, 'sixtytwo.yaml')).isFile()) {\n    throw new Error('invalid qualification configuration');\n  }","handlingStrategy":"try-catch","validationCode":"const fs = require('fs');\nconst path = require('path');\nfunction isQualificationConfigValid(configDirectory) {\n  let resolved;\n  try { resolved = fs.realpathSync.native(configDirectory); }\n  catch { return false; }\n  try {\n    return fs.statSync(resolved).isDirectory()\n      && fs.statSync(path.join(resolved, 'sixtytwo.yaml')).isFile();\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"// Distinguish the three failure modes the source conflates:\ntry {\n  validateNodeQualificationArgs(args, env);\n} catch (err) {\n  if (err.message.startsWith('--config-dir must exist')) {\n    // could be: missing dir, missing file, wrong type, or perms — re-check to disambiguate\n    const dirOk = fs.existsSync(configDir) && fs.statSync(configDir).isDirectory();\n    const yamlOk = dirOk && fs.statSync(path.join(configDir, 'sixtytwo.yaml')).isFile();\n    log.error('config-dir invalid', { dirOk, yamlOk, configDir });\n  }\n  throw err;\n}","preventionTips":["Treat the masked error-101 message as dead code; rely on error-102's text when debugging.","Add a preflight script that runs realpathSync/statSync and reports each check separately before invoking `ecc ito evals`.","If you maintain this file, refactor the try/catch at ito.js:126-138 so the inner validation message can surface."],"tags":["cli","validation","config","ito","evals","dead-code","bug"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}