koala73/worldmonitor · error · Error

renderCountryDevelopments requires a country name

Error message

renderCountryDevelopments requires a country name

What it means

build-crawlable-corpus.mjs exports renderCountryDevelopments(), which renders a country's frozen recent-developments section into HTML for the crawlable corpus. It derives a display name from countryName, trims it, and throws immediately if the trimmed result is empty, because a country page without a name cannot produce a valid ISO-heading-repaired section. The build fails loudly rather than publish a malformed or anonymous country brief.

Solutions

  1. Pass a non-empty countryName string: renderCountryDevelopments({ countryCode, countryName: country.name, developments })
  2. Fix the upstream data source so every country record has a populated `name` field before the build consumes it
  3. If only the ISO code is available, resolve the code to a display name (country metadata map) before calling the renderer
  4. Add a per-record check that fails fast with a message naming the offending country record

Example fix

// before
const html = renderCountryDevelopments({ countryCode: 'de', developments });
// after
const countryName = COUNTRY_NAMES['de'];
if (!countryName?.trim()) throw new Error(`no name for country de`);
const html = renderCountryDevelopments({ countryCode: 'de', countryName, developments });
Defensive patterns

Strategy: validation

Validate before calling

export function assertValidCountryDevelopmentsInput({ countryName, developments }) {
  if (typeof countryName !== 'string' || !countryName.trim()) {
    throw new Error(`countryName must be a non-empty string, got ${JSON.stringify(countryName)}`);
  }
  if (developments !== null && typeof developments !== 'object') {
    throw new Error('developments must be an object or null');
  }
}

Type guard

const hasCountryName = (c) =>
  typeof c?.countryName === 'string' && c.countryName.trim().length > 0;

Try / catch

try {
  html = renderCountryDevelopments({ countryCode, countryName, developments });
} catch (err) {
  if (err.message.includes('requires a country name')) {
    throw new Error(`country record ${countryCode} is missing a display name`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling renderCountryDevelopments({ countryCode, countryName, developments, ... }) with countryName undefined, null, an empty string, or a whitespace-only string (or a value that coerces to '' such as an empty object/array). countryCode defaults to '' but countryName does not, so omitting the property entirely also triggers this.

Common situations: Build-time config/data mistakes: a country metadata lookup returns an object missing `name`; a data file field was renamed from `name` to `label`; a generator passes through sparse rows for countries with partial data; a refactor switched callers to pass only countryCode, assuming the renderer derives the name from the code.

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/ed68ed2b5e1b96ae. Report an issue: GitHub.

Appendix: source

Thrown at scripts/build-crawlable-corpus.mjs:3323

    closeList();
    if (/^NEXT \d/i.test(trimmed)) {
      const colonIdx = trimmed.indexOf(':');
      if (colonIdx !== -1) {
        const label = applyCrawlableBriefEmphasis(escapeHtml(trimmed.slice(0, colonIdx)));
        const body = applyCrawlableBriefEmphasis(escapeHtml(trimmed.slice(colonIdx + 1).trim()));
        out.push(`          <p><strong>${label}:</strong> ${body}</p>`);
        continue;
      }
    }
    out.push(`          <p>${applyCrawlableBriefEmphasis(escapeHtml(trimmed))}</p>`);
  }
  closeList();
  return out.join('\n');
}

export function renderCountryDevelopments({ countryCode = '', countryName, developments, ciiEntry = null, pulse = null }) {
  const name = String(countryName || '').trim();
  if (!name) throw new Error('renderCountryDevelopments requires a country name');
  const rawRows = developments && typeof developments === 'object' ? developments : null;
  // Validate the frozen shape before the publish rules run: a malformed brief
  // must red the build, not be quietly withheld as thin grounding.
  if (rawRows?.brief && typeof rawRows.brief === 'object') assertDevelopmentsBrief(rawRows.brief);
  // Publish rules (#7738, #7748): markdown emphasis stripped, model preamble
  // dropped, the ISO-code heading repaired to the country name, and briefs
  // grounded on fewer than MIN_BRIEF_GROUNDING_PUBLISHERS withheld. loadCorpusData
  // already applied them to the committed snapshot; this call is idempotent
  // so direct callers get the same page.
  const rows = rawRows
    ? normalizeFrozenDevelopments(rawRows, { countryCode, countryName: name })
    : null;
  const headlines = Array.isArray(rows?.headlines) ? rows.headlines : [];
  const brief = rows?.brief && typeof rows.brief === 'object' ? rows.brief : null;
  const timeline = Array.isArray(rows?.timeline) ? rows.timeline : [];

  for (const headline of headlines) assertDevelopmentsHeadline(headline);
  if (brief) assertDevelopmentsBrief(brief);

View on GitHub (pinned to 7d06c8633d)