diff --git a/src/components/Docs404Tracking.astro b/src/components/Docs404Tracking.astro
new file mode 100644
index 000000000..d9f1bbf63
--- /dev/null
+++ b/src/components/Docs404Tracking.astro
@@ -0,0 +1,33 @@
+---
+/**
+ * Fires a Rudderstack `docs_404` track event with the originally-requested URL.
+ *
+ * This lives in a dedicated `.astro` component rather than inline in the
+ * `src/content/docs/404.mdx` body because MDX parses `{`/`}` as JavaScript
+ * expressions, which would break the tracking IIFE. Keeping the script in an
+ * `.astro` file lets it pass through untouched.
+ *
+ * The `docs_404` event (and its `broken_url` property) is consumed by the
+ * `weekly-404-monitor` agent to surface broken docs URLs. Do not rename the
+ * event or drop `broken_url` without updating that skill.
+ */
+---
+
+
diff --git a/src/content/docs/404.mdx b/src/content/docs/404.mdx
new file mode 100644
index 000000000..6e76c0370
--- /dev/null
+++ b/src/content/docs/404.mdx
@@ -0,0 +1,21 @@
+---
+title: Page not found
+description: The page you are looking for does not exist or has moved.
+template: splash
+---
+{/*
+ Custom 404 page. Starlight renders the `404` docs entry through its own
+ prerendered /404 route (see get404Route in @astrojs/starlight), so this
+ replaces the previous `src/pages/404.astro` — which defined a second /404
+ route and collided with Starlight's built-in one.
+
+ The component fires the `docs_404` Rudderstack event
+ consumed by the weekly-404-monitor agent; keep it on this page.
+*/}
+import Docs404Tracking from '@components/Docs404Tracking.astro';
+
+The page you are looking for does not exist or has been moved. Use the search or navigation to find what you need.
+
+[Go to the docs home](/)
+
+
diff --git a/src/middleware.ts b/src/middleware.ts
index 537591600..e42d5f581 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -17,6 +17,14 @@ import {
* negotiation and user-agent fallback detection (see `src/lib/docs-markdown.js`).
*/
export const onRequest = defineMiddleware(async (context, next) => {
+ // Content negotiation only applies to on-demand (SSR) requests. During the
+ // static prerender pass there is no real request, and reading
+ // `request.headers` warns ("not available on prerendered pages") once per
+ // route, which floods the build log. Skip it when the route is prerendered.
+ if (context.isPrerendered) {
+ return next();
+ }
+
const { request, url } = context;
if (!isEligibleDocHtmlPath(url.pathname)) {
diff --git a/src/pages/404.astro b/src/pages/404.astro
deleted file mode 100644
index 00b64a114..000000000
--- a/src/pages/404.astro
+++ /dev/null
@@ -1,74 +0,0 @@
----
-/**
- * Custom 404 page.
- *
- * Overrides Starlight's built-in 404 so we can fire a Rudderstack `docs_404`
- * track event with the originally-requested URL. Without this, every 404
- * visit logs `https://docs.warp.dev/404/` — hiding which paths are actually
- * broken.
- *
- * Uses StarlightPage so the full site chrome (nav, head, Rudderstack snippet,
- * Vercel Analytics) is inherited automatically.
- */
-import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
----
-
-
-
-
- The page you are looking for does not exist or has been moved. Use the search or navigation
- to find what you need.
-