santifer/career-ops · error · Error
payload must include at least one of: cv, articleDigest
Error message
payload must include at least one of: cv, articleDigest
What it means
Top-level validation in the pure `applyAdd(payload, opts)` core of add-entry.mjs. It requires `payload` to be an object carrying at least one of `cv` or `articleDigest`; otherwise nothing could be inserted and the call is meaningless. Thrown before any I/O so callers (and tests) get a fast, deterministic failure.
Source
Thrown at add-entry.mjs:147
}
return false;
}
export function appendArticleDigest(md, entry) {
const block = entry.replace(/\s+$/, '');
const base = md.replace(/\s+$/, '');
// Keep the existing `---`-separated block rhythm.
return `${base}\n\n---\n\n${block}\n`;
}
/**
* 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 };View on GitHub (pinned to 9b17a8ac97)
Solutions
- Structure the payload as `{ cv: { section, dedupKey, entry } }` and/or `{ articleDigest: { dedupKey, entry } }` — at least one must be present.
- If you only have a CV entry, still nest it: `applyAdd({ cv: { section, dedupKey, entry } })`.
- Validate the payload shape in your caller before invoking `applyAdd`; surface a clearer upstream error.
- Re-read the JSDoc above the function — it documents the exact `{ cv, articleDigest }` contract.
- Add a unit test exercising the empty-payload path to lock the contract.
Example fix
// before
applyAdd({ section: 'Experience', entry: '- Role @ X' }); // throws
// after
applyAdd({
cv: { section: 'Experience', dedupKey: 'role-x-2024', entry: '- Role @ X (2024)' }
}); Defensive patterns
Strategy: type-guard
Validate before calling
function isValidPayload(p) {
return !!p && typeof p === 'object' &&
(!!p.cv && typeof p.cv === 'object' || !!p.articleDigest && typeof p.articleDigest === 'object');
}
if (!isValidPayload(payload)) throw new Error('Supply { cv: {...} } and/or { articleDigest: {...} }'); Type guard
function isAddPayload(p) {
if (!p || typeof p !== 'object') return false;
const hasCv = p.cv && typeof p.cv === 'object';
const hasDigest = p.articleDigest && typeof p.articleDigest === 'object';
return hasCv || hasDigest;
} Prevention
- Always nest targets under `cv` or `articleDigest` — never at the top level.
- Validate shape in the caller before calling applyAdd.
- Use a builder helper that constructs the payload object to avoid typos.
- Lock the contract with a unit test on the empty/missing-target case.
When it happens
Trigger: Calling `applyAdd(null)`, `applyAdd({})`, `applyAdd({ cv: null, articleDigest: undefined })`, or `applyAdd('some string')`. Any shape missing both `payload.cv` and `payload.articleDigest` trips the guard.
Common situations: Agent/LLM calls `add` with only metadata (e.g. `{ section: 'Experience' }` at the top level instead of nested under `cv`); misreading the schema and passing the section/entry directly; empty payload from a tool wiring bug; calling add-entry programmatically before the caller has assembled either target.
Related errors
- payload.cv requires { section, entry }
- payload.articleDigest requires { entry }
- payload.cv requires a non-empty dedupKey (used for dedup/ide
- arbeitnow: unexpected API response on page ${page} — expecte
- workingnomads: unexpected API response — expected a JSON arr
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/448cce541191f41b.
Report an issue: GitHub.