santifer/career-ops · error
CV section order diverges from cv.md: rendered
Error message
CV section order diverges from cv.md: rendered ${renderedOrder}; cv.md ${sourceOrder} What it means
validateCvSectionOrder compares the section order of the rendered CV HTML against the heading order declared in cv.md (and, as a second chance, the canonical tailored order). If the rendered relative order matches neither, it throws — unless --allow-reorder was set, which downgrades the throw to a warning. It guards against an agent accidentally scrambling CV sections during tailoring.
Solutions
- Re-order the CV sections to match cv.md's heading order (or the canonical tailored order), then regenerate
- If the reorder is deliberate (e.g. Projects before Education for a technical role), re-run with --allow-reorder (or set allowReorder in the config/profile flow) to downgrade to a warning
- Check cv.md's heading order matches what you intend — the source of truth may itself be stale
- Inspect the rendered HTML section-title order against the order printed in the error message
- Set cv.sections in config/profile.yml so reorderCvSections applies the intended order before validation
Example fix
$ node generate-pdf.mjs --in cv.html --out cv.pdf Error: CV section order diverges from cv.md: rendered Education -> Projects -> Experience; cv.md Experience -> Projects -> Education # before $ node generate-pdf.mjs --in cv.html --out cv.pdf # after (deliberate reorder) $ node generate-pdf.mjs --in cv.html --out cv.pdf --allow-reorder
Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync } from 'node:fs';
const cv = readFileSync('cv.md', 'utf-8');
const headings = [...cv.matchAll(/^##\s+(.+)$/gm)].map(m => m[1].trim().toLowerCase());
const allowedOrders = [
['summary','competencies','experience','projects','education','certifications','awards','interests','skills'],
];
// verify the rendered section order matches cv.md headings or the canonical tailored order before generating Type guard
const orderMatches = (renderedKeys, referenceKeys) => renderedKeys.length >= 2 && renderedKeys.every((k, i) => i === 0 || referenceKeys.indexOf(k) > referenceKeys.indexOf(renderedKeys[i - 1]));
Try / catch
try {
validateCvSectionOrder(html, cvMarkdown);
} catch (err) {
if (err.message.startsWith('CV section order diverges')) {
console.warn(err.message, '— pass --allow-reorder if this reorder is deliberate');
return; // or rethrow in CI
}
throw err;
} Prevention
- Keep cv.md heading order as the source of truth and derive tailored CVs from it
- For deliberate reorders (Projects before Education), always pass --allow-reorder
- Set cv.sections in config/profile.yml so reorderCvSections applies the intended order before validation
- Diff rendered section titles against cv.md headings when hand-tailoring a CV
When it happens
Trigger: Rendering a tailored CV whose sections were reordered in a way that breaks both cv.md's order and the canonical tailored order (summary, competencies, experience, projects, education, certifications, awards, interests, skills) without passing --allow-reorder; or editing the HTML template/reorder step so sections come out shuffled.
Common situations: An agent hand-tailors a CV moving e.g. Awards before Experience in an order that matches neither reference; a custom template emits sections in a new order; a deliberate reorder done by the user without knowing the --allow-reorder escape hatch exists.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- ⚠️ (proceeding — --allow-reorder set)
- ⚠️ config/profile.yml cv.sections lists only
- ⚠️ config/profile.yml cv.sections lists
- Fact check failed ` : ''}
- 4dayweek: invalid URL
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/3d505bacb47d77d2.
Report an issue: GitHub.
Appendix: source
Thrown at generate-pdf.mjs:491
// CV tailored per modes/pdf.md's documented order looks like. Only treat it
// as a real problem if it ALSO fails to match that canonical order.
const canonicalComparable = rendered.filter(section => CANONICAL_TAILORED_POSITIONS.has(section.key));
if (canonicalComparable.length >= 2
&& findOrderDivergence(canonicalComparable, CANONICAL_TAILORED_POSITIONS) === -1) {
return;
}
const renderedOrder = renderedComparable.map(section => section.title).join(' -> ');
const sourceOrder = source
.filter(section => renderedComparable.some(renderedSection => renderedSection.key === section.key))
.map(section => section.title)
.join(' -> ');
const message = `CV section order diverges from cv.md: rendered ${renderedOrder}; cv.md ${sourceOrder}`;
if (allowReorder) {
console.warn(`⚠️ ${message} (proceeding — --allow-reorder set)`);
return;
}
throw new Error(message);
}
/**
* Every canonical section key the alias table can produce, in template order.
* Derived from the table rather than restated so the two cannot drift.
*/
export const CV_SECTION_KEYS = [...new Set(SECTION_ALIASES.values())];
// The all-caps comments the templates use to delimit sections, matched exactly
// as cv-sections-core.mjs matches them when stripping empty sections.
const SECTION_MARKER_RE = /<!--\s+[A-Z][A-Z ]*-->/g;
const SECTION_TITLE_RE = /class=["'][^"']*\bsection-title\b[^"']*["'][^>]*>([\s\S]*?)<\/[^>]+>/gi;
const DISPLAY_TITLE_MAX = 60;
/**
* A rendered section title, made safe to quote back in a console warning.
*View on GitHub (pinned to aac998c7ed)