santifer/career-ops · error · Error
Invalid page budget "${maxPages}". Use a positive integer.
Error message
Invalid page budget "${maxPages}". Use a positive integer. What it means
Thrown by enforcePageBudget() in generate-pdf.mjs when the maxPages budget option is not a positive integer. The guard runs before comparing the rendered page count against the limit, so a fractional, zero, negative, or non-numeric maxPages (e.g. "2", 2.5, NaN) is rejected up front rather than silently letting a CV pass or fail the comparison. It is a configuration-validation error, not a rendering error.
Source
Thrown at generate-pdf.mjs:290
}
/**
* Decide whether a rendered CV fits its configured page budget.
*
* This is deliberately separate from rendering: page count comes from the
* PDF Chromium actually produced, and the renderer never changes layout to
* force content under the limit.
*
* @param {number} pageCount - Actual pages in the rendered PDF.
* @param {{ maxPages?: number, strictPages?: boolean }} [options]
* @returns {void}
*/
export function enforcePageBudget(pageCount, { maxPages = 2, strictPages = false } = {}) {
if (!Number.isInteger(pageCount) || pageCount < 1) {
throw new Error(`Could not determine the rendered PDF page count (received ${pageCount}).`);
}
if (!Number.isInteger(maxPages) || maxPages < 1) {
throw new Error(`Invalid page budget "${maxPages}". Use a positive integer.`);
}
if (pageCount <= maxPages) return;
const actualLabel = 'pages';
const allowedLabel = maxPages === 1 ? 'page' : 'pages';
const message =
`CV is ${pageCount} ${actualLabel}; the allowed maximum is ${maxPages} ${allowedLabel}. ` +
'Trim lower-priority bullets, older roles, secondary projects, or the competencies strip, then regenerate.';
if (strictPages) {
throw new Error(`${message} (--strict-pages requested)`);
}
console.warn(`⚠️ ${message} Continuing because overflow is warning-only by default; use --strict-pages to reject it.`);
}
/**
* Read the page count from the PDF catalog's root /Pages dictionary.View on GitHub (pinned to 9b17a8ac97)
Solutions
- Coerce and validate maxPages before calling: parse with Number(), then guard Number.isInteger(n) && n >= 1, falling back to the default of 2.
- If you intend "no limit", skip enforcePageBudget entirely rather than passing 0 or a sentinel.
- When reading from CLI, do: const maxPages = Number.isInteger(Number(arg)) ? Number(arg) : 2;
- Fix the upstream config so maxPages is an unquoted integer in portals.yml / profile.yml.
Example fix
// before
const maxPages = config.max_pages; // string "2" from YAML
enforcePageBudget(count, { maxPages });
// after
const raw = Number(config.max_pages);
const maxPages = Number.isInteger(raw) && raw >= 1 ? raw : 2;
enforcePageBudget(count, { maxPages }); Defensive patterns
Strategy: validation
Validate before calling
function safeMaxPages(raw) {
const n = typeof raw === 'number' ? raw : Number(raw);
if (!Number.isInteger(n) || n < 1) return 2; // sane default
return n;
}
const maxPages = safeMaxPages(config.max_pages);
enforcePageBudget(count, { maxPages }); Type guard
/** True for valid page budgets accepted by enforcePageBudget. */
function isPageBudget(v) {
return typeof v === 'number' && Number.isInteger(v) && v >= 1;
} Prevention
- Always coerce config/CLI-derived maxPages through Number() and an integer check before calling enforcePageBudget.
- Treat 0 or undefined as 'use the default (2)', not as 'unlimited' or a sentinel.
- Keep max_pages an unquoted integer in YAML/JSON config.
- Add a unit test that passes string/float/0/negative and asserts the guard throws with a clear message.
When it happens
Trigger: Calling enforcePageBudget(pageCount, { maxPages }) or generate-pdf with a CLI/config-derived maxPages that is a string ("2"), a float (1.5), 0, a negative number, NaN, or undefined-coerced garbage. The Number.isInteger(maxPages) || maxPages < 1 check fails for any of these.
Common situations: Parsing --max-pages from argv without Number() conversion; reading maxPages from a YAML/JSON config where it landed as a quoted string; passing a default of 0 to mean "unlimited"; float budgets like 2.5 from a slider/UI.
Related errors
- CV is ${pageCount} ${actualLabel}; the allowed maximum is ${
- CV section order diverges from cv.md: rendered ${renderedOrd
- Could not determine the rendered PDF page count (received ${
- Unsupported image type: ${extname(inputPath) || '(no extensi
- Invalid URL: ${url}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/d481446dad4cbaac.
Report an issue: GitHub.