{"record":{"id":"30ec0427f5b3a927","repo":"santifer/career-ops","slug":"malformed-benchmarks-file-at-path-expected-a-t","errorCode":null,"errorMessage":"Malformed benchmarks file at ${path}: expected a top-level \"benchmarks\" map","messagePattern":"Malformed benchmarks file at (.+?): expected a top-level \"benchmarks\" map","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"funnel-velocity.mjs","lineNumber":259,"sourceCode":"      sameDayExcluded,\n      censored,\n    };\n  }\n  return result;\n}\n\n// --- Benchmarks ---\nexport function loadBenchmarks(explicitPath) {\n  const path = explicitPath\n    || (existsSync(join(DATA_ROOT, 'config/benchmarks.yml')) ? join(DATA_ROOT, 'config/benchmarks.yml') : join(CODE_ROOT, 'templates/benchmarks.yml'));\n  let doc;\n  try {\n    doc = yaml.load(readFileSync(path, 'utf-8'));\n  } catch (err) {\n    throw new Error(`Cannot read benchmarks at ${path}: ${err.message}`);\n  }\n  if (!doc || typeof doc.benchmarks !== 'object' || doc.benchmarks === null) {\n    throw new Error(`Malformed benchmarks file at ${path}: expected a top-level \"benchmarks\" map`);\n  }\n  return { benchmarks: doc.benchmarks, path };\n}\n\n/** Classify an own-rate percentage against a benchmark's range (inclusive). */\nexport function classify(ownPct, metric) {\n  if (ownPct === null || ownPct === undefined || !metric || !Array.isArray(metric.range_pct)) return null;\n  const [lo, hi] = metric.range_pct;\n  const band = ownPct < lo ? 'below-range' : ownPct > hi ? 'above-range' : 'within-range';\n  const typical = metric.typical_pct;\n  return {\n    band,\n    ownPct,\n    rangePct: [lo, hi],\n    typicalPct: typical ?? null,\n    vsTypical: typical ? Math.round((ownPct / typical) * 10) / 10 : null,\n    source: metric.source ?? null,\n    year: metric.year ?? null,","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/funnel-velocity.mjs#L241-L277","documentation":"loadBenchmarks successfully parsed the YAML but the resulting document does not contain a non-null top-level `benchmarks` map. The function requires doc.benchmarks to be an object; an empty file, a bare scalar, an array, or a document keyed differently all fail this structural check and throw with the file path.","triggerScenarios":"benchmarks.yml exists but is empty; parses to null/a string/a list; or uses a top-level key other than `benchmarks` (e.g. `funnel:` or content nested under a comment header).","commonSituations":"A user rewrote the file from scratch guessing the format; a truncated or templated file with only comments; copying an unrelated YAML into config/benchmarks.yml.","solutions":["Open the file at the printed path and add/restore a top-level `benchmarks:` map.","Restore the canonical shape from templates/benchmarks.yml in the repo.","If the file was meant as config for another tool, move it; benchmarks.yml must key everything under `benchmarks:`."],"exampleFix":"# before (malformed)\nfunnel:\n  applied_to_own: [10, 25]\n# after\nbenchmarks:\n  applied_to_own: [10, 25]","handlingStrategy":"validation","validationCode":"import {readFileSync} from 'fs'; import yaml from 'js-yaml';\nconst doc = yaml.load(readFileSync('templates/benchmarks.yml','utf8'));\nif (!doc || typeof doc.benchmarks !== 'object' || doc.benchmarks === null) throw new Error('benchmarks.yml must have a top-level \"benchmarks\" map');","typeGuard":"const hasBenchmarks = (d) => !!d && typeof d === 'object' && !Array.isArray(d) && typeof d.benchmarks === 'object' && d.benchmarks !== null;","tryCatchPattern":"try { loadBenchmarks(); } catch (e) { if (/Malformed benchmarks/.test(e.message)) { restoreTemplateAndRetry(); } else throw e; }","preventionTips":["Always keep `benchmarks:` as the single top-level key.","Never leave the file empty or comment-only.","Copy from templates/benchmarks.yml when editing rather than writing from memory."],"tags":["yaml","schema","config"],"backgroundTag":"schema-validation-failed","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}