{"record":{"id":"dae413dd6f2d6547","repo":"santifer/career-ops","slug":"template-where-missing-required-placeholders-v-missing-map-m","errorCode":null,"errorMessage":"Template ${where} missing required placeholders: ${v.missing.map((m) => `{{${m}}}`).join(', ')}","messagePattern":"Template (.+?) missing required placeholders: (.+?)\\}\\}`\\)\\.join\\(', '\\)\\}","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cv-templates.mjs","lineNumber":272,"sourceCode":"  // Every by-name caller lands here — build-cv-latex.mjs, generate-cover-letter.mjs.\n  const found = discover(kind, { dir, format });\n\n  let entry = found.get(chosen);\n  if (!entry && fallback && chosen !== 'standard') {\n    chosen = 'standard';\n    entry = found.get(chosen);\n  }\n  if (!entry) {\n    throw new Error(`Template not found for kind=${kind} name=${chosen} (${fileFor(chosen)})`);\n  }\n  const path = entry.path;\n  if (format === 'html') {\n    const v = validateTemplate(path, kind);\n    if (!v.ok) {\n      // Name the file that is actually short, not the flat filename it would\n      // have had. For a pack these differ, and the flat name points at nothing.\n      const where = entry.pack ? `${entry.pack}/${fileFor(chosen)}` : fileFor(chosen);\n      throw new Error(\n        `Template ${where} missing required placeholders: ${v.missing.map((m) => `{{${m}}}`).join(', ')}`\n      );\n    }\n  }\n  return path;\n}\n\n// ---- CLI ----\nconst isMain = isMainModule(import.meta.url);\nif (isMain) {\n  const argv = process.argv.slice(2);\n  const cmd = argv[0];\n  const kind = argv[1];\n  const flags = Object.fromEntries(\n    argv.filter((a) => a.startsWith('--')).map((a) => {\n      const [k, v] = a.replace(/^--/, '').split('=');\n      return [k, v ?? true];\n    })","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/cv-templates.mjs#L254-L290","documentation":"resolveTemplate validates that HTML CV templates contain all required placeholders (e.g. {{name}}, {{experience}}) before returning the template path. If a template file passes initial resolution but lacks any placeholder the CV generator will substitute, validation fails and this error is thrown, naming the actual file (pack-qualified when the template comes from a pack). It exists to fail fast at template-resolution time instead of producing a silently broken CV with unsubstituted tokens.","triggerScenarios":"Calling resolveTemplate with format === 'html' (directly or via CV generation) where validateTemplate(path, kind) returns {ok:false, missing:[...]} for the chosen template — i.e. a hand-edited, custom, or pack-shipped HTML template that dropped one or more {{placeholder}} tokens, or renamed one to something the generator does not recognize.","commonSituations":"Users customize templates/cv-template.html and accidentally delete a section wrapper containing a placeholder; a third-party CV pack's HTML file was edited or is from an older template contract version; a template was converted from the LaTeX variant (different placeholder names) and used as HTML; a rename inside the template didn't match the generator's expected placeholder set.","solutions":["Open the file named in the error message and re-add the listed {{placeholder}} tokens exactly as shown (they are rendered verbatim in the message).","If you don't need a custom design, restore the stock templates/cv-template.html (git checkout templates/cv-template.html or re-copy from templates/).","If the template comes from a pack, update the pack or fix the pack-qualified file `<pack>/<fileFor(chosen)>` named in the error.","If the placeholder list itself is wrong for your use case, update the required-placeholder definition in validateTemplate rather than the template.","As a last resort, set format to 'latex'/'tex' path if your template is a .tex file, since validation only runs for format === 'html'."],"exampleFix":"// before: template missing the contact block after a redesign edit\n<div class=\"experience\">{{experience}}</div>\n\n// after: restore the required placeholders the validator expects\n<div class=\"header\">\n  <h1>{{name}}</h1>\n  <p>{{contact}}</p>\n</div>\n<div class=\"experience\">{{experience}}</div>","handlingStrategy":"validation","validationCode":"import { validateTemplate } from './cv-templates.mjs';\nconst v = validateTemplate(templatePath, kind);\nif (!v.ok) {\n  console.error(`Fix placeholders before generating: ${v.missing.map(m => `{{${m}}}`).join(', ')}`);\n  process.exit(1);\n}","typeGuard":"function templateHasPlaceholders(html, required) {\n  return required.every(p => html.includes(`{{${p}}}`));\n}","tryCatchPattern":"try {\n  const path = await resolveTemplate({ format: 'html', kind });\n} catch (err) {\n  if (err.message.includes('missing required placeholders')) {\n    console.error('Template is missing tokens; restore stock template or re-add:', err.message);\n  } else throw err;\n}","preventionTips":["Run validateTemplate (or a placeholder grep) as a pre-commit hook on any edits to templates/*.html","Keep pack templates in sync with the placeholder contract after generator updates","Diff custom templates against the stock template after each career-ops update","Never delete a section outright — replace its contents while keeping the {{placeholder}} token"],"tags":["template","validation","placeholders","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"}