{"record":{"id":"d3e8794488aa4062","repo":"santifer/career-ops","slug":"invalid-format-entryformat-use-validforma","errorCode":null,"errorMessage":"invalid format \"${entryFormat}\" (use: ${validFormats.join(', ')})","messagePattern":"invalid format \"(.+?)\" \\(use: (.+?)\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"generate-pdf.mjs","lineNumber":1266,"sourceCode":"  } catch (err) {\n    if (err?.code !== 'ENOENT') throw err;\n  }\n  // One profile governs the whole batch, so the declared order is read once\n  // rather than per entry. Anchored to workspaceRoot for the same reason the\n  // single render is: it is the anchor readStyleTokens() and the cv.md read\n  // already use, so one profile.yml supplies every setting.\n  const cvSectionOrder = readCvSectionOrder(resolve(workspaceRoot, 'config', 'profile.yml'));\n\n  for (let i = 0; i < manifest.length; i++) {\n    const spec = manifest[i];\n    try {\n      if (!spec || typeof spec.input !== 'string' || typeof spec.output !== 'string') {\n        throw new Error('each entry needs a string \"input\" and \"output\"');\n      }\n\n      const entryFormat = (spec.format || globals.format).toLowerCase();\n      if (!validFormats.includes(entryFormat)) {\n        throw new Error(`invalid format \"${entryFormat}\" (use: ${validFormats.join(', ')})`);\n      }\n\n      const entryReport = (spec.reportNum ?? '').toString().trim();\n      if (entryReport && !/^\\d+$/.test(entryReport)) {\n        throw new Error(`invalid reportNum \"${entryReport}\" (use the numeric report number)`);\n      }\n\n      // Resolve manifest-supplied input/output relative to the manifest's own\n      // directory, not process.cwd(), so a manifest renders identically wherever\n      // the batch is launched from. Absolute paths in the manifest still win\n      // (resolve() ignores the base when the tail is absolute).\n      const entryInput = resolve(manifestDir, spec.input);\n      const entryOutput = resolve(manifestDir, spec.output);\n\n      // Path-containment guards (realpath-based): keep the read and write inside\n      // the tracker workspace even through a symlinked ancestor. A batch\n      // manifest that escapes the workspace is malformed/tampered and is\n      // recorded as a per-entry failure rather than read or written.","sourceCodeStart":1248,"sourceCodeEnd":1284,"githubUrl":"https://github.com/santifer/career-ops/blob/60398d6549a46f5266929538af21cfab94badc75/generate-pdf.mjs#L1248-L1284","documentation":"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.","triggerScenarios":"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.","commonSituations":"Porting manifests from tools where 'a5' or 'legal' are valid; assuming format means the output file type; editor autocomplete inserting the wrong token.","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."],"exampleFix":"// before\n{ \"input\": \"output/a.html\", \"output\": \"output/a.pdf\", \"format\": \"A5\" }\n\n// after\n{ \"input\": \"output/a.html\", \"output\": \"output/a.pdf\", \"format\": \"a4\" }","handlingStrategy":"validation","validationCode":"const VALID = ['a4', 'letter'];\nconst bad = manifest\n  .filter(e => e.format !== undefined && !VALID.includes(String(e.format).toLowerCase()))\n  .map(e => e.format);\nif (bad.length) { console.error(`Invalid format(s) ${bad.join(', ')} — use: ${VALID.join(', ')}`); process.exit(1); }","typeGuard":"/** @param {unknown} v */\nfunction isValidFormat(v) {\n  return v === undefined || (typeof v === 'string' && ['a4', 'letter'].includes(v.toLowerCase()));\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["batch","manifest","enum","paper-size"],"backgroundTag":"invalid-enum-value","analyzedSha":"60398d6549a46f5266929538af21cfab94badc75","analyzedAt":"2026-08-20T23:00:06.764Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}