{"record":{"id":"0f28a10700bfbd8c","repo":"srbhr/Resume-Matcher","slug":"missing-placeholders-0f28a1","errorCode":"missing_placeholders","errorMessage":"missing_placeholders","messagePattern":"missing_placeholders","errorType":"http","errorClass":"HTTPException","httpStatus":422,"severity":"error","filePath":"apps/backend/app/routers/config.py","lineNumber":434,"sourceCode":"    request: FeaturePromptsRequest,\n) -> FeaturePromptsResponse:\n    \"\"\"Update custom feature prompts.\n\n    Non-empty prompts are validated for the three required placeholders\n    (``{job_description}``, ``{resume_data}``, ``{output_language}``).\n    Missing placeholders return a 422 with a structured detail so the UI\n    can list exactly which ones are absent. Empty strings clear the\n    override — persisted as ``\"\"`` so runtime resolution falls back to the\n    built-in default.\n    \"\"\"\n    stored = _load_config()\n\n    if request.cover_letter_prompt is not None:\n        prompt = request.cover_letter_prompt.strip()\n        if prompt:\n            missing = validate_prompt_placeholders(prompt)\n            if missing:\n                raise HTTPException(\n                    status_code=422,\n                    detail={\n                        \"code\": \"missing_placeholders\",\n                        \"field\": \"cover_letter_prompt\",\n                        \"missing\": missing,\n                    },\n                )\n        stored[\"cover_letter_prompt\"] = prompt\n\n    if request.outreach_message_prompt is not None:\n        prompt = request.outreach_message_prompt.strip()\n        if prompt:\n            missing = validate_prompt_placeholders(prompt)\n            if missing:\n                raise HTTPException(\n                    status_code=422,\n                    detail={\n                        \"code\": \"missing_placeholders\",","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/routers/config.py#L416-L452","documentation":"A structured 422 validation error with detail {code:'missing_placeholders', field:'cover_letter_prompt', missing:[...]} raised by update_feature_prompts. validate_prompt_placeholders found that the supplied cover letter prompt is missing required template placeholders (e.g. {job_description}, {company}), which would break content generation.","triggerScenarios":"PUT/POST feature prompts with a non-empty cover_letter_prompt that omits one or more required placeholders; typically after hand-editing a prompt and deleting a placeholder token.","commonSituations":"User rewrites a prompt for tone and accidentally removes a variable; copy-pasting a prompt from docs of a different version with different placeholder requirements.","solutions":["Add the placeholders listed in detail.missing back into cover_letter_prompt","Copy the default prompt as a starting point and edit around the placeholders","If the prompt is intentionally empty, send null or an empty string instead of a partial prompt"],"exampleFix":"// before\nprompt = \"Write a friendly cover letter.\"\n// after\nprompt = \"Write a friendly cover letter for {company} based on: {job_description}\"","handlingStrategy":"validation","validationCode":"const REQUIRED = ['{job_description}', '{company}']\nconst missing = REQUIRED.filter(p => !prompt.includes(p))\nif (missing.length) throw new Error(`missing placeholders: ${missing.join(', ')}`)","typeGuard":null,"tryCatchPattern":"try {\n  await api.updateFeaturePrompts({ cover_letter_prompt: prompt })\n} catch (e) {\n  const d = e.response?.data?.detail\n  if (d?.code === 'missing_placeholders') {\n    highlightField('cover_letter_prompt', `Missing: ${d.missing.join(', ')}`)\n  } else throw e\n}","preventionTips":["Edit prompts starting from the default template so placeholders stay intact","Validate placeholders client-side before saving","Use token-preserving editors (protect {…} spans from deletion)","Surface detail.missing directly in the UI next to the field"],"tags":["validation","http-422","prompt","placeholders","template"],"backgroundTag":"missing-template-placeholder","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}