koala73/worldmonitor · error
is missing the evaluation section
Error message
is missing the evaluation section
What it means
applyComparisonNarrative enforces that each comparison page has an evaluation section: a truthy evaluationHeading plus a non-empty evaluationProse array. The section is a mandatory SEO/content block; its absence fails the build.
Solutions
- Add evaluationHeading and a non-empty evaluationProse array to the slug's narrative.
- Check key spelling in the narrative object.
- Restore any evaluation prose removed during copy editing.
- Copy the evaluation section shape from an existing passing narrative as a template.
Example fix
// before
'worldmonitor-vs-x': { heading: '...', switchHeading: '...' }
// after
'worldmonitor-vs-x': {
heading: '...',
evaluationHeading: 'How we evaluated',
evaluationProse: ['We compared coverage, update frequency and pricing across both tools.'],
} Defensive patterns
Strategy: validation
Validate before calling
if (!narrative.evaluationHeading || !narrative.evaluationProse?.length) {
throw new Error(page.slug + ' missing evaluation section');
} Type guard
const hasEvaluation = (n) => typeof n.evaluationHeading === 'string' && n.evaluationHeading.trim() !== '' && Array.isArray(n.evaluationProse) && n.evaluationProse.length > 0;
Try / catch
try {
page = applyComparisonNarrative(page);
} catch (e) {
if (String(e.message).includes('missing the evaluation section')) {
console.error('Add evaluationHeading + evaluationProse for:', e.message);
} else throw e;
} Prevention
- Start new narratives from a template containing all mandatory sections.
- Keep a per-slug content checklist (evaluation, switch, methodology) in the authoring docs.
- Run the build locally before committing narrative edits.
When it happens
Trigger: Running the build when a slug's merged narrative has no evaluationHeading (empty/undefined) or evaluationProse is missing/empty.
Common situations: Creating a new narrative entry and skipping the evaluation section template; a copy edit that removed the prose; misspelled keys (evalutationHeading, evaluationProse vs evaluationParagraphs).
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Missing comparison narrative for ' + page.slug
- is missing whyWeWinBody
- is missing the switch-trigger section
- /accuracy/ meta description must be 155–160 chars (got ${len
- FAQ count must be 8-12, got ' + faqs.length
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/c6cb7c0e892c37af.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/build-comparison-pages.mjs:474
if (faqNames.has(key)) {
throw new Error(page.slug + ' duplicate FAQ question: ' + question);
}
faqNames.add(key);
}
const merged = { ...page, ...narrative, faqs };
delete merged.extraFaqs;
const whyBody = (merged.whyWeWinBody ?? []).join(' ').replace(/\s+/g, ' ').trim();
if (!whyBody) {
throw new Error(page.slug + ' is missing whyWeWinBody');
}
if (whyBody === merged.whyWeWin.replace(/\s+/g, ' ').trim()) {
throw new Error(page.slug + ' whyWeWinBody must not repeat whyWeWin');
}
if (merged.heading && !(merged.headingProse?.length || merged.competitorProfiles?.length)) {
throw new Error(page.slug + ' H2 "' + merged.heading + '" has no following prose');
}
if (!merged.evaluationHeading || !merged.evaluationProse?.length) {
throw new Error(page.slug + ' is missing the evaluation section');
}
if (!merged.switchHeading || !merged.switchProse?.length) {
throw new Error(page.slug + ' is missing the switch-trigger section');
}
if (!merged.methodologyProse?.length) {
throw new Error(page.slug + ' is missing methodology prose');
}
return merged;
}
export const COMPARISON_PAGES = COMPARISON_PAGE_SEEDS.map(applyComparisonNarrative);
function renderParagraphs(paragraphs, escapeHtml) {
return (paragraphs ?? []).map((paragraph) => ' <p>' + escapeHtml(paragraph) + '</p>');
}
function renderHeadingSection(heading, paragraphs, escapeHtml, label) {
if (!heading) return [];View on GitHub (pinned to 7d06c8633d)