santifer/career-ops · error · Error
payload.cv requires
Error message
payload.cv requires { section, entry } What it means
When payload.cv is present, applyAdd destructures { section, dedupKey, entry } from it and requires at minimum a non-empty `section` (which cv.md section to insert into) and an `entry` (the markdown content to add). A truthy payload.cv missing either means the caller shaped the CV part of the payload incorrectly, so there is no well-defined insertion to perform.
Solutions
- Provide both fields: applyAdd({ cv: { section: 'Projects', dedupKey: '...', entry: '- ...' } }).
- If passing a raw string, wrap it: { cv: { section: <targetHeading>, dedupKey: <uniqueKey>, entry: <markdownText> } }.
- Pick a section name that exactly matches an existing heading in cv.md so insertIntoCvSection can find it.
Example fix
// before
await applyAdd({ cv: 'Built cv-santiago portfolio' }, { cvText });
// after
await applyAdd(
{ cv: { section: 'Projects', dedupKey: 'proj:cv-santiago', entry: '- **cv-santiago** — open-source portfolio' } },
{ cvText }
); Defensive patterns
Strategy: validation
Validate before calling
function isValidCvPayload(cv) {
return Boolean(cv && cv.section && cv.entry);
}
if (payload.cv && !isValidCvPayload(payload.cv)) throw new Error('cv payload needs { section, entry }'); Type guard
function isCvTarget(cv) {
return typeof cv === 'object' && cv !== null && typeof cv.section === 'string' && cv.section.length > 0 && typeof cv.entry === 'string' && cv.entry.length > 0;
} Try / catch
try {
applyAdd({ cv: cvTarget }, { cvText });
} catch (e) {
if (e.message.includes('payload.cv requires')) {
console.error(`Malformed cv payload: ${JSON.stringify(cvTarget)}`);
} else throw e;
} Prevention
- Wrap payload construction in a helper enforcing the { section, dedupKey, entry } shape.
- Validate with a JSON schema or zod schema before calling applyAdd.
- Keep the target section name copied from an actual cv.md heading.
When it happens
Trigger: applyAdd({ cv: { section: 'Projects' } }) (no entry), applyAdd({ cv: { entry: '...' } }) (no section), or applyAdd({ cv: { section: '', entry: '...' } }) — truthy payload.cv but empty/absent section or entry.
Common situations: Hand-writing the payload and forgetting a field, constructing { cv: 'my entry text' } (a string instead of the required object), or a refactor that moved `section`/`entry` to a different nesting level.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- payload.articleDigest requires
- apify: entry has invalid field_map. Each of title, url…
- Existing candidates file at
- Gemini returned an invalid career-ops report
- invalid golden case : need string id/jd and label.
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/2140ace8d53c317b.
Report an issue: GitHub.
Appendix: source
Thrown at add-entry.mjs:180
}
/**
* Pure core: given the current file contents and a payload, compute the new
* contents and a per-target status. No I/O — this is what the tests exercise.
* @returns {{ cv: string, articleDigest: string, result: object }}
*/
export function applyAdd(payload, { cvText = null, articleText = null } = {}) {
if (!payload || typeof payload !== 'object' || (!payload.cv && !payload.articleDigest)) {
throw new Error('payload must include at least one of: cv, articleDigest');
}
const result = {};
let cv = cvText;
let articleDigest = articleText;
if (payload.cv) {
const { section, dedupKey, entry } = payload.cv;
if (!section || !entry) throw new Error('payload.cv requires { section, entry }');
// dedupKey is what makes the insert idempotent — refuse to add without one
// rather than silently allowing duplicate re-runs.
if (!normalizeKey(dedupKey)) throw new Error('payload.cv requires a non-empty dedupKey (used for dedup/idempotency)');
if (cvText === null) throw new Error(`cv.md not found — cannot add to a CV that does not exist`);
if (cvHasEntry(cvText, section, dedupKey)) {
result.cv = { status: 'duplicate', section };
} else {
cv = insertIntoCvSection(cvText, section, entry);
result.cv = { status: 'added', section };
}
}
if (payload.articleDigest) {
const { dedupKey, entry } = payload.articleDigest;
if (!entry) throw new Error('payload.articleDigest requires { entry }');
if (!normalizeKey(dedupKey)) throw new Error('payload.articleDigest requires a non-empty dedupKey (used for dedup/idempotency)');
// article-digest.md is optional; create it from a header when missing.
const current = articleText === nullView on GitHub (pinned to aac998c7ed)