santifer/career-ops · error · Error

payload.articleDigest requires { entry }

Error message

payload.articleDigest requires { entry }

What it means

Per-target validation in `applyAdd` for the `articleDigest` payload: when present, it must include a non-empty `entry` (the proof-point text to append). Unlike the cv branch, `dedupKey` is checked by a separate guard immediately after, but the entry itself is the first mandatory field because there's nothing to append without it.

Source

Thrown at add-entry.mjs:171

  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 === null
      ? '# Article Digest -- Proof Points\n\nCompact proof points from portfolio projects. Read by career-ops at evaluation time.\n'
      : articleText;
    if (articleDigestHasEntry(current, dedupKey)) {
      result.articleDigest = { status: 'duplicate' };
      articleDigest = articleText;
    } else {
      articleDigest = appendArticleDigest(current, entry);
      result.articleDigest = { status: articleText === null ? 'created' : 'added' };
    }
  }

  return { cv, articleDigest, result };
}

async function readStdin() {

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Include a non-empty `entry` string in `payload.articleDigest` (the actual proof-point line to append).
  2. Use the exact key names `{ dedupKey, entry }` — do not substitute `text`/`body`/`content`.
  3. Generate the entry eagerly upstream; if generation fails, do not call applyAdd at all.
  4. Add a caller-side guard: `if (p.articleDigest && !p.articleDigest.entry) throw ...`.
  5. Cover both missing-entry and missing-dedupKey paths in tests.

Example fix

// before
applyAdd({ articleDigest: { dedupKey: 'kpi-x' } }); // throws — no entry
// after
applyAdd({
  articleDigest: {
    dedupKey: 'kpi-x',
    entry: '- KPI X: cut p95 latency 40% via caching (2024)'
  }
});
Defensive patterns

Strategy: validation

Validate before calling

function validateDigestPayload(d) {
  return !!d && typeof d === 'object' &&
    typeof d.entry === 'string' && d.entry.trim() !== '';
}
if (payload.articleDigest && !validateDigestPayload(payload.articleDigest)) {
  throw new Error('payload.articleDigest needs non-empty { entry }');
}

Type guard

function isDigestEntry(d) {
  return !!d && typeof d === 'object' &&
    typeof d.entry === 'string' && d.entry.trim() !== '';
}

Prevention

When it happens

Trigger: Calling `applyAdd({ articleDigest: { dedupKey: 'x' } })` (no entry); `applyAdd({ articleDigest: {} })`; `applyAdd({ articleDigest: { entry: '' } })`. Any truthy `payload.articleDigest` object without a non-empty `entry`.

Common situations: Caller wires up the digest dedupKey but forgets to attach the generated proof-point text; entry is built from a template that returned empty; agent passes the metadata shape but not the content; misreading the schema and putting the text under a different key (e.g. `text`, `body`).

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/01c9193230dad3ac. Report an issue: GitHub.