koala73/worldmonitor · error · Error

empty sitemap: ${location}

Error message

empty sitemap: ${location}

What it means

After extracting <loc> values from every entry of a fetched sitemap, getPublishedBatches throws this when the resulting `urls` array is empty — the sitemap document exists and parses into entries but contains no locations (or no entries at all), so there is nothing to submit to IndexNow.

Solutions

  1. Check why the sitemap generator produced no URLs — verify pages are eligible (not excluded by noindex/robots or build filters) and rerun the generator.
  2. Fetch the sitemap manually to confirm whether the deployment serves the real file or an empty/placeholder document; redeploy if stale.
  3. Purge the CDN/edge cache for the sitemap URL after regenerating.
  4. For the root sitemap specifically, ensure SITEMAP_INDEX_MEMBERS are generated so the index is never empty.

Example fix

// before (empty served sitemap)
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></urlset>

// after
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url><loc>https://example.com/</loc></url>
</urlset>
Defensive patterns

Strategy: validation

Validate before calling

const xml = await res.text();
if (!/<(url|sitemap)>[\s\S]*<\/(url|sitemap)>/.test(xml)) {
  throw new Error(`sitemap has no entries, skipping IndexNow submit: ${url}`);
}

Try / catch

try {
  const batches = await getPublishedBatches(origin);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('empty sitemap')) {
    console.warn(`Sitemap is empty; nothing to submit: ${err.message}`);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Fetching `location` returns XML where the entry regex matches nothing (e.g. an empty `<urlset></urlset>` or `<sitemapindex></sitemapindex>`), or all matched candidates were HTML comments and were filtered out, leaving `urls.length === 0`.

Common situations: A fresh deploy publishes an empty sitemap before content is generated; the sitemap generator filtered out every URL (all pages excluded via robots/noindex); a cache or placeholder document is served instead of the real sitemap.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/08cba864c042d489. Report an issue: GitHub.

Appendix: source

Thrown at scripts/seo-indexnow-submit.mjs:194

      method: 'GET',
      redirect: 'manual',
      signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
      headers: { Accept: 'application/xml', 'User-Agent': USER_AGENT },
    });
    if (response.status !== 200) throw new Error(`${location} returned ${response.status}, expected direct 200`);
    const source = (await response.text()).trim();
    const root = /^(?:<\?xml[^?]*\?>\s*)?<(sitemapindex|urlset)\b[^>]*>([\s\S]*)<\/\1>\s*$/.exec(source);
    if (!root) throw new Error(`invalid sitemap document: ${location}`);
    const tag = root[1] === 'sitemapindex' ? 'sitemap' : 'url';
    const entryPattern = new RegExp(`<!--[\\s\\S]*?-->|<${tag}>[\\s\\S]*?<\\/${tag}>`, 'g');
    const entries = [...root[2].matchAll(entryPattern)].filter(([entry]) => !entry.startsWith('<!--'));
    if (root[2].replace(entryPattern, '').trim()) throw new Error(`invalid sitemap entries: ${location}`);
    const urls = entries.map(([entry]) => {
      const locations = [...entry.matchAll(/<loc>\s*([^<]+?)\s*<\/loc>/g)];
      if (locations.length !== 1) throw new Error(`expected one location per sitemap entry: ${location}`);
      return decodeXml(locations[0][1].trim());
    });
    if (urls.length === 0) throw new Error(`empty sitemap: ${location}`);
    if (location === `${origin}/sitemap.xml`
      && (root[1] !== 'sitemapindex' || urls.length !== SITEMAP_INDEX_MEMBERS.length
        || new Set(urls).size !== urls.length || urls.some(url => !SITEMAP_INDEX_MEMBERS.includes(url)))) {
      throw new Error('published root sitemap members do not match the declared inventory');
    }
    if (root[1] === 'sitemapindex') {
      pending.push(...urls);
    } else {
      for (const url of urls) {
        const page = new URL(url);
        if (page.protocol !== 'https:' || !hosts.has(page.host) || page.username || page.password || page.hash || page.pathname.endsWith('.xml')) {
          throw new Error(`invalid published page URL: ${url}`);
        }
        pages.add(url);
      }
    }
  }
  for (const family of ['docs', 'blog']) {

View on GitHub (pinned to 7d06c8633d)