withastro/astro · error · AstroError
ForbiddenRewrite
ForbiddenRewrite
Error message
You tried to rewrite the on-demand route '${from}' with the static route '${to}', when using the 'server' output.
The static route '${to}' is rendered by the component
'${component}', which is marked as prerendered. This is a forbidden operation because during the build, the component '${component}' is compiled to an
HTML file, which can't be retrieved at runtime by Astro. What it means
AstroErrorData.ForbiddenRewrite is thrown when a rewrite targets a prerendered route from an on-demand (SSR) route while the manifest is server-like. During build, prerendered routes compile to plain HTML files and disappear from the server manifest, so the running server has no component to render for them — the rewrite is impossible by construction, not merely unsupported.
Solutions
- Remove `export const prerender = true` from the target route so it stays renderable on demand
- Redirect instead of rewriting: return Astro.redirect(target) — static HTML files are still served, so the URL change is safe
- If the target must stay prerendered, link to it or fetch its content server-side instead of rewriting
Example fix
// before
return Astro.rewrite('/prerendered-page');
// after
return Astro.redirect('/prerendered-page'); Defensive patterns
Strategy: try-catch
Try / catch
import { AstroError } from 'astro/errors';
try {
return await Astro.rewrite(target);
} catch (err) {
if (err instanceof AstroError && err.code === 'ForbiddenRewrite') {
// target is prerendered — redirect instead; the static file is still served
return Astro.redirect(target);
}
throw err;
} Prevention
- Before rewriting, confirm the target route does not export prerender = true
- Prefer redirects toward prerendered pages — they work regardless of output mode
- When enabling prerender on a route, grep the codebase for rewrites pointing at it
When it happens
Trigger: Astro.rewrite('/prerendered-page') or next('/prerendered-page') from an SSR route, when the target has `export const prerender = true` and the project builds with output 'server'.
Common situations: Marking marketing/docs pages prerendered for performance while app pages rewrite into them; migrating a site from static to server output where old rewrites now point at pages that became static; shared routing tables that mix both kinds of routes.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- A collision will result in a hard error in following…
- AdapterSupportOutputMismatch
- context.rewrite is not available in Astro.
- Couldn't find component for route
- ForbiddenRewrite
AI-assisted analysis of withastro/astro@157c500c38 (2026-08-18).
Data as JSON: /api/errors/75bedbbf4cc93b0d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/core/middleware/sequence.ts:78
} else {
const request =
handleContext.request.method === 'GET' || handleContext.request.method === 'HEAD'
? handleContext.request
: handleContext.request.clone();
const newUrl =
payload instanceof URL ? payload : new URL(payload, handleContext.url.origin);
newRequest = copyRequest(newUrl, request, false, state.logger, routeData.route);
}
// This is a case where the user tries to rewrite from a SSR route to a prerendered route (SSG).
// This case isn't valid because when building for SSR, the prerendered route disappears from the server output because it becomes an HTML file,
// so Astro can't retrieve it from the emitted manifest.
if (
manifest.serverLike === true &&
handleContext.isPrerendered === false &&
routeData.prerender === true
) {
throw new AstroError({
...ForbiddenRewrite,
message: ForbiddenRewrite.message(
handleContext.url.pathname,
pathname,
routeData.component,
),
hint: ForbiddenRewrite.hint(routeData.component),
});
}
carriedPayload = payload;
handleContext.request = newRequest;
handleContext.url = new URL(newRequest.url);
handleContext.params = getParams(routeData, pathname);
handleContext.routePattern = routeData.route;
setOriginPathname(
handleContext.request,
oldPathname,View on GitHub (pinned to 157c500c38)