koala73/worldmonitor · error
is missing whyWeWinBody
Error message
is missing whyWeWinBody
What it means
applyComparisonNarrative requires every page's merged content to include a non-empty whyWeWinBody array (joined and whitespace-normalized must be non-empty). This is the expanded 'why we win' prose that follows the summary claim; a page with only the headline whyWeWin text is rejected.
Solutions
- Add a whyWeWinBody array of paragraph strings to the slug's COMPARISON_NARRATIVES entry.
- Ensure the entries are non-empty after whitespace normalization.
- Check the field name spelling in the narrative object.
- Make sure whyWeWinBody does not simply duplicate whyWeWin (that throws separately).
Example fix
// before
'worldmonitor-vs-x': { whyWeWin: 'More datasets.' }
// after
'worldmonitor-vs-x': {
whyWeWin: 'More datasets.',
whyWeWinBody: ['WorldMonitor fuses maritime, aviation and conflict feeds into one live map.'],
} Defensive patterns
Strategy: validation
Validate before calling
const body = (narrative.whyWeWinBody ?? []).join(' ').replace(/\s+/g, ' ').trim();
if (!body) throw new Error(page.slug + ' needs non-empty whyWeWinBody'); Type guard
const hasWhyBody = (n) => Array.isArray(n.whyWeWinBody) && n.whyWeWinBody.some((s) => String(s).trim() !== '');
Try / catch
try {
page = applyComparisonNarrative(page);
} catch (e) {
if (String(e.message).includes('is missing whyWeWinBody')) {
console.error('Author whyWeWinBody paragraphs for:', e.message);
} else throw e;
} Prevention
- Use a narrative template/checklist that includes whyWeWinBody as a required field.
- Never leave the array empty as a placeholder; stub with a TODO string caught in review.
- Add a CI content audit that lists all slugs missing required prose fields.
When it happens
Trigger: Running the build when a slug's narrative lacks whyWeWinBody entirely, sets it to an empty array, or contains only empty/whitespace strings.
Common situations: Authoring a new comparison narrative and filling whyWeWin but not the body list; copy-editing that emptied the array; a merge step where the field key was misspelled (whyWeWinBodies etc.).
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 the evaluation section
- 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/36e47ed6b6dcfea3.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/build-comparison-pages.mjs:465
throw new Error('Missing comparison narrative for ' + page.slug);
}
const faqs = [...page.faqs, ...(narrative.extraFaqs ?? [])];
if (faqs.length < 8 || faqs.length > 12) {
throw new Error(page.slug + ' FAQ count must be 8-12, got ' + faqs.length);
}
const faqNames = new Set();
for (const [question] of faqs) {
const key = String(question).trim().toLowerCase();
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;
}View on GitHub (pinned to 7d06c8633d)