Sitemap Still References Old Domain After Migration

After a domain move, sitemap.xml still lists old-domain URLs and Search Console flags 'URL not allowed.' Find the stale site-URL config and fix it for good.

You migrated from old.com to new.com, set up redirects, and added the new property in Search Console. But you open https://new.com/sitemap.xml and the URLs inside still say <loc>https://old.com/article</loc>. Search Console marks the sitemap with “URL not allowed” and the note “Check that the URLs all begin with the same domain as your sitemap location.” The redirects work fine, so this feels wrong — but Google discards every <loc> whose host does not match the host that served the sitemap. A sitemap full of old-domain URLs served from the new domain indexes exactly zero pages.

Fastest fix: the host is almost always baked in at build time from one config value (site, siteUrl, or baseURL). Update that one value to https://new.com, rebuild, redeploy, purge the CDN, and resubmit. The rest of this page is about finding which config value, and confirming nothing else still hardcodes the old host.

Why Google rejects it (the rule you’re hitting)

Per the sitemaps.org protocol and Google’s sitemap docs, every URL in a sitemap must be on the same host as the sitemap file. Same host means the full origin matches: scheme (http vs https), www vs bare domain, and the registered domain all have to be identical. There is no cross-domain sitemap submission feature — you cannot legitimately list old.com URLs in a sitemap hosted on new.com. So the only valid fix is making the sitemap emit new.com URLs.

Which bucket are you in

Symptom in the sitemapMost likely causeWhere to look
Every <loc> is https://old.com/...Stale site-URL build configsite / siteUrl / baseURL
URLs are new.com but http:// not https://, or www vs bare flipsWrong scheme/host form in same configSame config value, check the exact string
sitemap-index.xml is correct but a sub-sitemap is oldOnly part of the build regenerated, or one hardcoded scriptEach sitemap-*.xml file
Local build is correct, production is oldCDN/edge cachecurl with a cache-buster
robots.txt Sitemap: line points at old.comGenerator wrote the old host there toorobots.txt / generator config

Common causes

Ordered by hit rate, highest first.

1. Astro site: config still points to the old URL

In astro.config.mjs:

export default defineConfig({
  site: 'https://old.com',  // ← bug
});

@astrojs/sitemap reads the root site value to compose absolute URLs, so a stale site produces a stale sitemap. Note two Astro specifics that trip people up: site lives in the root defineConfig, not inside the sitemap() call, and if site is missing entirely Astro logs a warning and skips the sitemap altogether rather than guessing the deploy URL. The default output files are sitemap-index.xml and sitemap-0.xml (then sitemap-1.xml, etc. past 45,000 URLs), so check those exact names — not a bare sitemap.xml.

How to spot it: open astro.config.mjs and read the site value. If it is old, that is the whole bug.

2. Next.js siteUrl still resolves to the old host

next-sitemap.config.js:

module.exports = {
  siteUrl: process.env.SITE_URL || 'https://old.com',
  generateRobotsTxt: true,
};

siteUrl is required by next-sitemap. If SITE_URL is not set in the production environment, it falls back to the hardcoded old URL. next-sitemap runs as a postbuild script, so a build that “succeeded” can still emit an old-host sitemap. It also writes the Sitemap: line (and an optional host) into robots.txt, which is a second place the old domain hides.

How to spot it: check .env.production and your host’s environment-variable panel for SITE_URL, then run cat public/robots.txt (or the deployed robots.txt) and confirm the Sitemap: line.

3. Hugo baseURL not updated

In config.toml / hugo.toml (or config/_default/hugo.toml):

baseURL = "https://old.com"

Hugo bakes baseURL into every generated absolute URL, including the sitemap and any RSS feeds.

How to spot it: grep -rn "baseURL" config/ hugo.toml config.toml 2>/dev/null.

4. A custom sitemap script has the host hardcoded

Some sites build the sitemap with a homegrown script that string-concatenates a hardcoded host. The migration updated the framework config but never touched the script.

How to spot it: grep -rn "old.com" scripts/ src/ public/.

5. CDN / edge cache is serving the old sitemap

You updated the config and redeployed, but Cloudflare, Vercel’s edge, Fastly, or Netlify is still serving the previously cached sitemap.xml.

How to spot it: compare a normal fetch against a cache-busted one.

curl -s "https://new.com/sitemap.xml" | grep -m1 "<loc>"
curl -s "https://new.com/sitemap.xml?nocache=$(date +%s)" | grep -m1 "<loc>"

If the cache-busted response shows new.com but the plain one shows old.com, it is a cache. Purge the CDN (Cloudflare: Caching → Configuration → Purge Everything, or purge /sitemap*.xml specifically) and refetch.

6. Sitemap is split, and only the index regenerated

The site has sitemap-index.xml referencing sitemap-0.xml, sitemap-articles.xml, sitemap-pages.xml, etc. The index updated but a sub-sitemap (often one generated by a separate step or plugin) still lists old URLs.

How to spot it: open the index, follow every child <loc>, and check each sub-sitemap.

Shortest path to fix

Step 1: Find the site-URL config

Look in the one place your stack composes absolute URLs:

  • Astro: astro.config.mjs → root site:
  • Next.js: next-sitemap.config.js, next.config.js, and the production SITE_URL env var
  • Hugo: config.toml / hugo.tomlbaseURL
  • SvelteKit: svelte.config.js adapter config, or whatever env var your sitemap route reads
  • WordPress (Yoast/RankMath): Settings → General → Site Address (URL), then regenerate the sitemap
  • Custom: grep -rniE "site_?url|baseurl|canonical" . --exclude-dir=node_modules

Step 2: Set it to the new canonical URL

Use the exact scheme and host form (https://, and www or bare — match what actually serves the sitemap):

// Astro — astro.config.mjs
site: 'https://new.com',
# Hugo — hugo.toml
baseURL = "https://new.com"
# Next.js — .env.production (or platform env panel)
SITE_URL=https://new.com

Step 3: Rebuild and inspect locally before deploying

npm run build
grep -h "<loc>" dist/sitemap*.xml | head -20   # Astro outputs to dist/

Every <loc> should now read https://new.com/.... Also check the generated robots.txt:

grep -i "sitemap\|host" dist/robots.txt public/robots.txt 2>/dev/null

Step 4: Verify on production

curl -s "https://new.com/sitemap-index.xml" | head -20
curl -s "https://new.com/sitemap-0.xml" | grep -c "old.com"   # expect 0

If old.com still appears, you are looking at a cache (see cause 5) — purge and refetch.

Step 5: Submit the corrected sitemap and remove the old entry

In the new Search Console property: Sitemaps → enter sitemap.xml (or sitemap-index.xml, whichever you serve) → Submit. If the old property still has a sitemap registered, delete that entry there so Google stops reprocessing old-host URLs.

Step 6: Add a CI guard so it can’t regress

# Run after build in CI
if grep -rq "old.com" dist/sitemap*.xml dist/robots.txt; then
  echo "ERROR: build artifacts still reference old.com"
  exit 1
fi

How to confirm it’s fixed

  1. curl -s https://new.com/sitemap-index.xml and every child sitemap return only https://new.com <loc> values (run the grep -c "old.com" check → 0).
  2. robots.txt’s Sitemap: line points at new.com.
  3. In Search Console, the sitemap status moves from “URL not allowed” to Success with a discovered-URL count above 0. This can take a few hours to a few days to reprocess after resubmission.

Easy to misdiagnose as

People assume the hosting platform “auto-detects” the deploy URL. Most static generators do not — they bake the host from your config at build time. A correct redirect from old.com to new.com also does not fix the sitemap: Google reads the literal <loc> host and never follows the redirect during sitemap parsing. The redirect helps users and link equity; it does nothing for sitemap host matching.

Prevention

  • Keep one source of truth for the site URL (a single config value or env var) and derive everything — sitemap, canonical, OG, RSS — from it.
  • Add the CI assertion above so a stale host fails the build, not the index.
  • After any domain change, build locally and inspect sitemap-*.xml and robots.txt before deploying.
  • Audit every sub-sitemap and any custom script, not just sitemap-index.xml.
  • After deploying, always cache-bust the sitemap once to rule out an edge cache.

FAQ

  • What is the exact Search Console error? “URL not allowed,” with the description “Check that the URLs all begin with the same domain as your sitemap location.” It appears per-sitemap in the Sitemaps report.
  • My redirects from old.com work — why does Google still reject the sitemap? Sitemap parsing reads the literal <loc> host and does not follow redirects. The host in <loc> must equal the host serving the sitemap, scheme and www included.
  • Can I submit my old-domain URLs in the new sitemap so Google migrates faster? No. There is no cross-domain sitemap submission. Mixed hosts are rejected; serve only new.com URLs.
  • How long until Google reprocesses the corrected sitemap? Status usually updates within hours to a couple of days after resubmission; full re-indexing of all pages takes longer. Resubmitting in Search Console nudges it.
  • Does www vs non-www matter? Yes. https://new.com and https://www.new.com are different hosts to a sitemap parser. The <loc> host must match the URL that actually served the sitemap file.
  • Can I keep two sitemaps temporarily? Yes — one per language or per section is fine, as long as every URL in each one uses the canonical host.

Tags: #Domain #DNS #SSL #Troubleshooting #Sitemap #Old domain