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

  1. Add evaluationHeading and a non-empty evaluationProse array to the slug's narrative.
  2. Check key spelling in the narrative object.
  3. Restore any evaluation prose removed during copy editing.
  4. 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

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


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)