Skip to content
Abdulkader Safi

Filament Atelier

The sitemap was not broken, it just looked it

18 August 2026 Updated 18 August 2026 1 min read
A sitemap rendered in a browser as a styled table of URLs, last modified dates and locale badges.

A sitemap opened in a browser as a wall of unlabelled URLs and timestamps in a serif font. The XML was valid, correctly typed and parsed cleanly. What was missing is the thing every serious sitemap ships and mine did not, and the fix is one processing instruction crawlers ignore entirely.

v0.1.6 fixes one thing, and the interesting part is that nothing was actually wrong.

The report was that /sitemap.xml looked broken. What came back when opened in a browser was a single line of URLs and timestamps run together, in a serif font, with no structure at all:

http://localhost:8000/home 2026-08-18T14:02:07+00:00 http://localhost:8000/ar/home …

That is the classic shape of XML being parsed as HTML: unknown tags render as nothing, text nodes survive, and you get the content with all the markup dropped.

Proving it before fixing it

The temptation is to start changing headers. I checked the response first, because the fix for "browser renders it oddly" and the fix for "the file is malformed" are completely different.

Content-Type: application/xml; charset=UTF-8
00000000: 3c3f 786d 6c20 7665 7273 696f 6e3d 2231  <?xml version="1

Correct type, first bytes are the XML declaration, no byte order mark, and simplexml_load_string parsed it in the test suite. The file was fine.

There was also a second claim in the same report: a draft page appearing in the sitemap. That one I could check directly, and the timestamps told the story. The Contact page had published_at set several minutes after my seed ran, so it had been published in the panel while the site was open. The sitemap was right to list it.

Both halves of a bug report can be worth checking separately, and one of them being real does not make the other one real.

What was actually missing

An <?xml-stylesheet?> instruction. Every sitemap you have seen rendered as a neat table has one, and mine did not.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://example.com/sitemap.xsl"?>
<urlset …>

Browsers apply the stylesheet and render a table of URLs, last-modified dates and locale alternates. Crawlers ignore the instruction entirely, so nothing about the machine-readable side changes. It is presentation for humans bolted onto a file written for robots, which is a slightly odd idea until you remember that the person opening it is usually the developer who just built it.

The stylesheet is served from the package rather than published into the host app's public directory, so it cannot drift from the XML it renders and there is nothing extra to publish or forget.

Verifying the fix, not the string

The lazy test here asserts that the output contains xml-stylesheet. That proves a line exists, not that the stylesheet works.

So I ran the actual transform the way a browser does:

xsltproc sitemap.xsl sitemap.xml

Which produced 4218 bytes of HTML with a table, six URLs, the right dates, and working per-locale links. That is the difference between testing that you wrote something and testing that it does something.

The test in the suite asserts both: that the instruction sits between the declaration and the root element, which is the only place it is allowed, and that the XML still parses with it there.

The other thing this cost

While chasing it I also spent a while on a page rendering with no CSS at all, in both the public site and the editor preview.

Nothing in the code. A stale public/hot file was sitting there pointing at a Vite dev server that was not running, so every page linked its stylesheet to a dead port. Vite writes that file on start and removes it on a clean exit, so killing the dev server hard leaves it behind and every page silently loses its styling until you delete it.

It was already the last entry in my troubleshooting docs, filed under "still stuck". It has since been promoted, because the symptom as experienced is "everything is unstyled" and nobody looks in a section called still stuck first.

Where it stands

v0.1.6. One processing instruction, one stylesheet served from the package, and a sitemap that reads as a table when a person opens it.

No migration, no API change. The kind of release that exists because a thing being correct and a thing looking correct are not the same, and only one of them gets reported.