koala73/worldmonitor · error
is missing following prose
Error message
is missing following prose
What it means
renderHeadingSection renders an H2 plus its paragraphs for a comparison page. A heading with no following body text produces an empty section, which is both an SEO/content quality problem and an invalid page shape, so the build throws '<label|heading> is missing following prose' when renderParagraphs returns nothing for a heading.
Solutions
- Populate the prose array paired with that heading in the page seed (check the field name matches what applyComparisonNarrative merges, e.g. switchProse for switchHeading).
- If the section is intentionally absent, remove the heading too — a heading without prose is what triggers the throw.
- Re-run the build and confirm the section renders with at least one <p>.
Example fix
// before switchHeading: 'When to switch tools', switchProse: [], // after switchHeading: 'When to switch tools', switchProse: [ 'Switch to World Monitor when you need sub-daily updates across ...', ],
Defensive patterns
Strategy: validation
Validate before calling
for (const [heading, prose] of [['evaluation', page.evaluationProse], ['switch', page.switchProse]]) {
if (heading && !(Array.isArray(prose) && prose.length)) throw new Error(`${page.slug}: ${heading} heading has no prose`);
} Type guard
const hasHeadingProse = (p) => typeof p === 'object' && p !== null && Array.isArray(p.prose) && p.prose.length > 0;
Prevention
- Keep heading and prose fields adjacent in the seed object so one is never added without the other.
- Lint seeds for paired heading/prose keys before running the build.
When it happens
Trigger: renderHeadingSection called with a truthy heading whose paragraphs argument is undefined, null, [], or an array of empty strings, causing body.length === 0.
Common situations: A seed defines a heading (e.g. evaluationHeading, switchHeading) but the corresponding prose array key is misspelled or missing; content editors emptied the paragraph array; a refactor renamed the prose field but not the heading field.
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
- H2 "' + page.heading + '" has no following content
- is missing methodology prose
- profile "' + profile.name + '" has no prose
- needs a World Monitor measurement explanation
- needs a summary for the llms.txt Comparisons section
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/1993c074a1279d21.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/build-comparison-pages.mjs:495
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 [];
const body = renderParagraphs(paragraphs, escapeHtml);
if (body.length === 0) {
throw new Error((label || heading) + ' is missing following prose');
}
return [' <h2>' + escapeHtml(heading) + '</h2>', ...body];
}
function renderKeywordSection(page, escapeHtml) {
const headingProse = page.headingProse ?? [];
const profiles = page.competitorProfiles ?? [];
const profileBlocks = profiles.flatMap((profile) => {
if (!profile.paragraphs?.length) {
throw new Error(page.slug + ' profile "' + profile.name + '" has no prose');
}
const tag = page.heading ? 'h3' : 'h2';
return [
' <' + tag + '>' + escapeHtml(profile.name) + '</' + tag + '>',
...renderParagraphs(profile.paragraphs, escapeHtml),
];
});
if (page.heading) {View on GitHub (pinned to 7d06c8633d)