Skip to content

🐛 Stop doubling the prefix on a proxied site's sitemap - #509

Closed
taras wants to merge 1 commit into
productionfrom
fix/proxy-sitemap-double-prefix
Closed

taras wants to merge 1 commit into
productionfrom
fix/proxy-sitemap-double-prefix

Conversation

@taras

@taras taras commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Motivation

Production has not deployed since 2026-09-18. Every run since 2026-09-27
21:57 UTC fails at the Staticalize step with 519 download errors, all of them
404s on a doubled path:

Error: could not download http://127.0.0.1:8005/effection/effection/docs/resources
  Error: GET http://127.0.0.1:8005/effection/effection/docs/resources responded 404 Not Found

The cause is upstream and intentional. thefrontside/effection#1248 merged at
21:53 and moved Effection's production --base to
https://frontside.com/effection — the url it actually lives at. Its sitemap
now says so:

<!-- effection.netlify.app/sitemap.xml -->
<loc>https://frontside.com/effection/docs</loc>

Where it used to say https://effection.netlify.app/docs.

parseSitemapUrls takes url.pathname and prepends /${prefix} to every
entry. That was right while upstream advertised a site-relative path. Now the
path already carries the mount point, so the prefix lands on it twice and
staticalize is asked for 519 urls that are nowhere.

Interactors and Graphgen still advertise their own origin, which is why only
Effection's 519 entries break — but that is a bug in those sites, not a
property to design around. frontside.com/interactors/docs/quick-start
currently serves <link rel="canonical" href="https://interactors.netlify.app/docs/quick-start">,
so this site disclaims its own content in favour of a Netlify subdomain, and
Graphgen emits no canonical at all. Both should move their --base the way
Effection just did; this change is what lets them, since it accepts a sitemap
whether or not it carries the mount.

Approach

A path already under the mount is left alone; one that is not still gets it:

export function prefixed(path: string, prefix: string): string {
  let mount = `/${prefix}`;

  if (path === mount || path.startsWith(`${mount}/`)) {
    return posixNormalize(path);
  }

  return posixNormalize(`${mount}${path}`);
}

Deciding on the path rather than the origin is what makes this cover every
case. An Effection preview is staticalized with its own alias url as the base,
so its sitemap has no prefix and still needs one — an origin comparison would
get that wrong, since the alias origin is neither frontside.com nor
effection.netlify.app.

The startsWith test includes the trailing slash so a sibling like
/effectionx is not mistaken for the mount.

Tests

This repo has no test setup, so I exercised the real sitemapExtension against
all three live upstream sitemaps.

Before, on production:

effection    entries= 519  doubled=519  e.g. /effection/effection/search
interactors  entries=  73  doubled=0    e.g. /interactors/docs/quick-start

After, on this branch:

effection    entries= 519  correctly mounted= 519  doubled=0
             e.g. /effection/  /effection/search
interactors  entries=  73  correctly mounted=  73  doubled=0
             e.g. /interactors/  /interactors/docs/quick-start
graphgen     entries=  13  correctly mounted=  13  doubled=0
             e.g. /graphgen/  /graphgen/docs/introduction

519 is exactly the number of failures in the deploy log, and exactly the number
of entries in Effection's sitemap.

I also checked the mounting rule directly, including an Effection preview's
unprefixed paths and the /effectionx sibling:

ok  effection   /effection/docs        -> /effection/docs
ok  effection   /docs                  -> /effection/docs
ok  effection   /effectionx/thing      -> /effection/effectionx/thing
ok  interactors /docs/quick-start      -> /interactors/docs/quick-start
ok  graphgen    /                      -> /graphgen/

I could not generate the full local /sitemap.xml end to end — that route also
calls the Simplecast API, which 401s without a real token — so I drove the proxy
extension directly instead. That is the code this changes.

deno check routes/proxy-route.ts reports 6 errors on this branch. It reports
the same 6 on production: pre-existing hast type mismatches, untouched here.

Note

#508 (staticalize 0.3.0) is failing on this same error and is unrelated to it —
its own change is a version bump, and the sitemap-reading code is byte-identical
between 0.2.7 and 0.3.0. It should go green once this lands.

Deploys have failed since effection started publishing under its real home.
thefrontside/effection#1248 moved its production `--base` to
`https://frontside.com/effection`, so every `<loc>` in the sitemap it serves
now carries the mount point rather than a site-relative path.

`parseSitemapUrls` added `/effection` to all of them regardless, asking
staticalize for 519 urls under `/effection/effection` that are nowhere. The
crawl reported 519 errors and exited non-zero, which is the whole deploy.

A path already under the mount is left alone. One that is not still gets it,
so Interactors and Graphgen — which advertise their own origin — are
unchanged, and so is an Effection preview, whose base is its own alias url.

Deciding on the path rather than the origin covers all three, and a sibling
such as `/effectionx` is not mistaken for the mount.
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

🚀 Deploy Preview Ready!

Frontside creates cohesive developer experiences for Cloud Native Teams
Frontside creates cohesive developer experiences for Cloud Native Teams

@taras

taras commented Sep 30, 2026

Copy link
Copy Markdown
Member Author

Closing: the cause is fixed at the source, so there is nothing left for this to
tolerate.

Effection's sitemap started naming frontside.com/effection because
thefrontside/effection#1248 pointed its --base there to get the canonical url
right. --base moves every self-referencing url, the sitemap included, so the
entries arrived here already carrying the mount point and parseSitemapUrls
added it a second time.

thefrontside/staticalize#22 split that into --base for where a build is
hosted and --canonical for the url it is published at, and
thefrontside/effection#1255, thefrontside/interactors#333 and
thefrontside/graphgen#74 all moved onto it. Their sitemaps are site-relative
again:

effection.netlify.app/sitemap.xml      <loc>https://effection.netlify.app/</loc>
interactors.netlify.app/sitemap.xml    <loc>https://interactors.netlify.app/</loc>
graphgen-data.netlify.app/sitemap.xml  <loc>https://graphgen-data.netlify.app/</loc>

So the mount works the way it always did, and this change would never run.

For the record, in case this comes back: the idempotent mount is still correct
on its own terms — an entry that already names its mount point is at that path,
and adding the prefix twice is wrong whatever produced it. The scenario that
would make it matter again is the sitemap moving to --canonical, which is
noted as an open question in thefrontside/staticalize#21. If that happens, this
is the change to bring back.

@taras taras closed this Sep 30, 2026

This branch was successfully deployed

1 active deployment
Preview — 357d9e4c Deployed Sep 28, 2026 by taras via deploy-preview #145
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant