santifer/career-ops · error · Error
invalid format "${entryFormat}" (use: ${validFormats.join(',
Error message
invalid format "${entryFormat}" (use: ${validFormats.join(', ')}) What it means
Each batch entry's format — or the batch-global format when the entry omits it — is lowercased and must be one of validFormats = ['a4', 'letter'] (generate-pdf.mjs:1239). Uppercase is fine ('A4' passes via toLowerCase), but any other paper size or a value like 'pdf' is rejected per-entry.
Source
Thrown at generate-pdf.mjs:1266
} catch (err) {
if (err?.code !== 'ENOENT') throw err;
}
// One profile governs the whole batch, so the declared order is read once
// rather than per entry. Anchored to workspaceRoot for the same reason the
// single render is: it is the anchor readStyleTokens() and the cv.md read
// already use, so one profile.yml supplies every setting.
const cvSectionOrder = readCvSectionOrder(resolve(workspaceRoot, 'config', 'profile.yml'));
for (let i = 0; i < manifest.length; i++) {
const spec = manifest[i];
try {
if (!spec || typeof spec.input !== 'string' || typeof spec.output !== 'string') {
throw new Error('each entry needs a string "input" and "output"');
}
const entryFormat = (spec.format || globals.format).toLowerCase();
if (!validFormats.includes(entryFormat)) {
throw new Error(`invalid format "${entryFormat}" (use: ${validFormats.join(', ')})`);
}
const entryReport = (spec.reportNum ?? '').toString().trim();
if (entryReport && !/^\d+$/.test(entryReport)) {
throw new Error(`invalid reportNum "${entryReport}" (use the numeric report number)`);
}
// Resolve manifest-supplied input/output relative to the manifest's own
// directory, not process.cwd(), so a manifest renders identically wherever
// the batch is launched from. Absolute paths in the manifest still win
// (resolve() ignores the base when the tail is absolute).
const entryInput = resolve(manifestDir, spec.input);
const entryOutput = resolve(manifestDir, spec.output);
// Path-containment guards (realpath-based): keep the read and write inside
// the tracker workspace even through a symlinked ancestor. A batch
// manifest that escapes the workspace is malformed/tampered and is
// recorded as a per-entry failure rather than read or written.View on GitHub (pinned to 60398d6549)
Solutions
- Set the entry's format to 'a4' or 'letter', matching the destination market's paper size.
- If all entries share one size, remove per-entry format and set the global format once.
- Remember casing is tolerated but the value itself is a fixed two-value enum.
Example fix
// before
{ "input": "output/a.html", "output": "output/a.pdf", "format": "A5" }
// after
{ "input": "output/a.html", "output": "output/a.pdf", "format": "a4" } Defensive patterns
Strategy: validation
Validate before calling
const VALID = ['a4', 'letter'];
const bad = manifest
.filter(e => e.format !== undefined && !VALID.includes(String(e.format).toLowerCase()))
.map(e => e.format);
if (bad.length) { console.error(`Invalid format(s) ${bad.join(', ')} — use: ${VALID.join(', ')}`); process.exit(1); } Type guard
/** @param {unknown} v */
function isValidFormat(v) {
return v === undefined || (typeof v === 'string' && ['a4', 'letter'].includes(v.toLowerCase()));
} Prevention
- Remember the enum is exactly a4 | letter — paper size, not file type.
- Set the format once globally and omit it from entries unless one CV needs a different size.
- Uppercase is fine; everything else is not.
When it happens
Trigger: Manifest entries with "format": "A5", "format": "legal", or "format": "pdf" (confusing file format with paper size); a typo like "lette"; a global format flag set to an invalid value that every entry inherits.
Common situations: Porting manifests from tools where 'a5' or 'legal' are valid; assuming format means the output file type; editor autocomplete inserting the wrong token.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- each entry needs a string "input" and "output"
- invalid reportNum "${entryReport}" (use the numeric report n
- output escapes the tracker workspace: ${entryOutput}
- Invalid or blocked URL: ${rejected.reason}
- Unsupported profile photo style: ${style} (expected rounded,
AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20).
Data as JSON: /api/errors/d3e8794488aa4062.
Report an issue: GitHub.