{"record":{"id":"6e34df61c8cd9489","repo":"santifer/career-ops","slug":"malformed-states-file-at-statespath-expected-a-6e34df","errorCode":null,"errorMessage":"Malformed states file at ${statesPath}: expected a top-level \"states\" list","messagePattern":"Malformed states file at (.+?): expected a top-level \"states\" list","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"tracker-utils.mjs","lineNumber":540,"sourceCode":"    rmSync(tmpPath, { force: true });\n    throw err;\n  }\n}\n\n/**\n * Load the canonical tracker states from `templates/states.yml`.\n *\n * states.yml is the single source of truth for the 8 canonical states and\n * their aliases. Parsing it here (instead of hardcoding the list) means a new\n * state or alias lands in one file and every consumer follows.\n *\n * @param {string} statesPath - Path to templates/states.yml.\n * @returns {{id:string,label:string,aliases:string[]}[]} Parsed state entries.\n */\nexport function loadCanonicalStates(statesPath) {\n  const doc = yaml.load(readFileSync(statesPath, 'utf-8'));\n  if (!doc || !Array.isArray(doc.states)) {\n    throw new Error(`Malformed states file at ${statesPath}: expected a top-level \"states\" list`);\n  }\n  return doc.states.map(s => ({\n    id: String(s.id ?? ''),\n    label: String(s.label ?? ''),\n    aliases: Array.isArray(s.aliases) ? s.aliases.map(String) : [],\n  }));\n}\n\n/**\n * Resolve user input to a canonical state label, strictly.\n *\n * Case-insensitive match against each state's label, id, and aliases, after\n * stripping markdown bold. Unlike merge-tracker's lenient batch normalization\n * (which defaults unknowns to \"Evaluated\" so a whole merge isn't lost), this\n * is the strict variant for interactive/CLI use: unknown input returns null so\n * the caller can reject it before anything touches the tracker.\n *\n * @param {string} input - Raw state text from the user or a script.","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/tracker-utils.mjs#L522-L558","documentation":"loadCanonicalStates() in tracker-utils.mjs reads templates/states.yml and, like loadLifecycle (error 355), requires a top-level `states` array. It throws an Error if the document is null or doc.states is not an array. This is the entry point used by set-status.mjs and the canonical state resolver, so a malformed file blocks all status updates.","triggerScenarios":"templates/states.yml is empty, has wrong top-level key, contains non-object YAML, or is truncated. Any state-writing operation (set-status.mjs, merge-tracker.mjs) that calls resolveCanonicalState -> loadCanonicalStates will surface this.","commonSituations":"Hand-editing states.yml and breaking the schema; a botched update-system.mjs run; a git merge conflict; an editor that auto-converted tabs/spaces breaking YAML parsing.","solutions":["Restore the canonical file: git checkout HEAD -- templates/states.yml.","Re-run node update-system.mjs apply.","Validate structure: node -e \"const y=require('js-yaml').load(require('fs').readFileSync('templates/states.yml','utf8')); console.assert(Array.isArray(y.states))\".","Run node verify-pipeline.mjs to catch related integrity issues."],"exampleFix":"# restore the single source of truth\ngit checkout HEAD -- templates/states.yml\nnode verify-pipeline.mjs","handlingStrategy":"validation","validationCode":"function validateStatesFile(statesPath) {\n  const doc = yaml.load(readFileSync(statesPath, 'utf-8'));\n  if (!doc || !Array.isArray(doc.states)) {\n    throw new Error(`states.yml missing 'states' list — restore: git checkout HEAD -- templates/states.yml`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const states = loadCanonicalStates(STATES_FILE);\n} catch (err) {\n  if (err.message.includes('Malformed states file')) {\n    console.error(err.message);\n    console.error('Restoring system file and retrying...');\n    execSync('git checkout HEAD -- templates/states.yml');\n    // retry after restore\n  } else throw err;\n}","preventionTips":["Treat templates/states.yml as read-only system data; never hand-edit.","Include a states.yml integrity check in verify-pipeline.mjs / CI.","Run node update-system.mjs apply after pulling repo updates."],"tags":["config","states-yml","tracker","yaml","config-integrity","set-status"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}