srbhr/Resume-Matcher · warning · FeaturePromptsError
missing_placeholders
missing_placeholders
Error message
Feature prompts validation error (missing_placeholders)
What it means
updateFeaturePrompts throws a FeaturePromptsError when the backend answers HTTP 422 with a structured detail whose code is 'missing_placeholders'. This means the server validated the submitted prompt templates and found required {placeholder} tokens (e.g. {job_description}, {resume}) absent from one of the prompts. Unlike the sibling errors this one carries the parsed detail object, letting the UI highlight exactly which prompt/placeholder is at fault.
Source
Thrown at apps/frontend/lib/api/config.ts:394
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(update),
});
if (!res.ok) {
// Error path: body may be absent or malformed, so we tolerate parse
// failure. A fetch body is a one-shot stream — read it once and reuse
// for both the 422-special-case and the generic fallback.
const errBody = (await res.json().catch(() => ({}))) as {
detail?: FeaturePromptsValidationError | string;
};
if (
res.status === 422 &&
typeof errBody.detail === 'object' &&
errBody.detail?.code === 'missing_placeholders'
) {
throw new FeaturePromptsError(errBody.detail);
}
// FastAPI can return ``detail`` as a string or a structured object.
// Stringifying an object via the ``||`` shortcut yields "[object Object]";
// serialize explicitly.
let message: string;
if (typeof errBody.detail === 'string') {
message = errBody.detail;
} else if (errBody.detail) {
message = JSON.stringify(errBody.detail);
} else {
message = `Failed to update feature prompts (status ${res.status}).`;
}
throw new Error(message);
}
// Success path: require a valid JSON body. Swallowing parse errors here
// would let an invalid success response be returned as FeaturePrompts
// with undefined fields — caller code would then read .cover_letter_promptView on GitHub (pinned to 116f9cc3b0)
Solutions
- Read err.detail (the FeaturePromptsError payload) to find which prompt is missing which placeholder, then re-insert the exact {placeholder} tokens in the Settings editor.
- Validate the prompt client-side before submitting: every required placeholder for the feature must appear in the string.
- If placeholders were lost via copy/paste, restore from the default prompt shown in the form and re-apply edits around the tokens.
- Catch FeaturePromptsError separately in the save handler and render a targeted message instead of the generic save error.
Example fix
// before
await updateFeaturePrompts({ cover_letter_prompt: 'Write a cover letter for this job.' });
// after
const prompt = 'Write a cover letter for {job_title} at {company_name} using {resume}.';
const required = ['{job_title}', '{company_name}', '{resume}'];
if (required.some((p) => !prompt.includes(p))) {
throw new Error('Prompt is missing required placeholders: ' + required.join(', '));
}
await updateFeaturePrompts({ cover_letter_prompt: prompt }); Defensive patterns
Strategy: validation
Validate before calling
const REQUIRED: Record<string, string[]> = {
cover_letter_prompt: ['{job_title}', '{company_name}', '{resume}'],
cold_outreach_prompt: ['{job_title}', '{company_name}', '{resume}'],
};
function missingPlaceholders(prompt: string, required: string[]): string[] {
return required.filter((p) => !prompt.includes(p));
} Type guard
function isFeaturePromptsError(e: unknown): e is FeaturePromptsError {
return e instanceof FeaturePromptsError;
} Try / catch
try {
await updateFeaturePrompts(update);
} catch (e) {
if (e instanceof FeaturePromptsError) {
highlightMissingPlaceholders(e.detail);
} else throw e;
} Prevention
- Validate placeholders in the form before submit, not just server-side
- Keep placeholders visually distinct (highlighted tokens) in prompt editors
- Restore defaults button to recover templates with intact placeholders
- Test prompt round-trips after i18n or template changes
When it happens
Trigger: Saving custom cover-letter or cold-outreach prompt text where a required placeholder was deleted or renamed — e.g. a user edits the cover_letter_prompt in Settings and removes '{job_description}' or '{company_name}', or a migration/import strips placeholders, or the frontend sends a prompt built without the tokens the backend template contract requires.
Common situations: Users hand-editing prompts in the Settings feature-prompts form and pasting text over the template placeholders; locale/translation flows that swap placeholder names; automated tests or scripts posting prompt JSON copied from an older schema.
Related errors
- ${data.detail || Failed to update prompt config (status ${re
- missing_base_url
- missing_placeholders
- ${message = data.detail or Failed to update LLM config (stat
- ${data.detail || Failed to update feature config (status ${r
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/68015710fe5e017f.
Report an issue: GitHub.