Astro Info
Astro v6.4.3
Vite v7.3.5
Node v24.16.0
System Linux (x64)
Package Manager npm
Output server
Adapter @astrojs/node (v10.1.3)
Integrations none
Also: hono v4.12.23.
Describe the Bug
With experimental.advancedRouting enabled and a custom src/app.ts built from the astro/hono
handlers (app.use(pages())), a page that throws during render returns a bare
Internal Server Error (Hono's default error response) with HTTP 500, instead of rendering the
project's src/pages/500.astro.
The same project renders the custom 404 page correctly for unmatched routes (after the fix for
#16907, shipped in astro@6.4.3), so the missing 500 handling is an asymmetry within the same
pipeline.
npm install && npm run build && npm start
curl -i http://localhost:4321/boom # HTTP 500, body: "Internal Server Error" (expected: src/pages/500.astro)
src/pages/boom.astro is just throw new Error('boom') at the top of its frontmatter;
src/pages/500.astro is <h1>my custom 500</h1>.
What's the expected result?
GET /boom should render src/pages/500.astro with HTTP 500, the same way a standard SSR app
does. Removing experimental.advancedRouting and src/app.ts (plain SSR) makes the identical
request correctly return HTTP 500 with <h1>my custom 500</h1>.
| Request |
advancedRouting + astro/hono |
plain SSR (no flag, no app.ts) |
GET /does-not-exist |
404 — my custom 404 ✅ |
404 — my custom 404 |
GET /boom |
500 — Internal Server Error ❌ |
500 — my custom 500 ✅ |
Root cause (suspected)
The astro/hono pages() handler (packages/astro/src/core/hono/index.ts) delegates straight to
the fetch pipeline, with no error handling:
function pages() {
return async (context, _honoNext) => {
return fetchPages(getFetchState(context));
};
}
fetchPages renders the matched route but does not wrap the render in a try/catch and never falls
back to getCustom500Route(...). The thrown error propagates out of the Hono middleware, so Hono's
default onError returns Internal Server Error.
The standard app pipeline catches the render error and serves the error page
(packages/astro/src/core/app/base.ts / core/routing/handler.ts →
renderError({ status: 500, ... }), which resolves getCustom500Route(...) and renders
500.astro).
#16907 added the symmetric getCustom404Route(...) to the fetch pipeline (so the 404 page is now
served for unmatched routes); the 500 counterpart for render-time errors is still missing.
Link to Minimal Reproducible Example
https://github.com/iseraph-dev/astro-hono-500-repro
Participation
Astro Info
Also:
honov4.12.23.Describe the Bug
With
experimental.advancedRoutingenabled and a customsrc/app.tsbuilt from theastro/honohandlers (
app.use(pages())), a page that throws during render returns a bareInternal Server Error(Hono's default error response) with HTTP 500, instead of rendering theproject's
src/pages/500.astro.The same project renders the custom 404 page correctly for unmatched routes (after the fix for
#16907, shipped in
astro@6.4.3), so the missing 500 handling is an asymmetry within the samepipeline.
src/pages/boom.astrois justthrow new Error('boom')at the top of its frontmatter;src/pages/500.astrois<h1>my custom 500</h1>.What's the expected result?
GET /boomshould rendersrc/pages/500.astrowith HTTP 500, the same way a standard SSR appdoes. Removing
experimental.advancedRoutingandsrc/app.ts(plain SSR) makes the identicalrequest correctly return HTTP 500 with
<h1>my custom 500</h1>.astro/honoapp.ts)GET /does-not-existmy custom 404✅my custom 404GET /boomInternal Server Error❌my custom 500✅Root cause (suspected)
The
astro/honopages()handler (packages/astro/src/core/hono/index.ts) delegates straight tothe fetch pipeline, with no error handling:
fetchPagesrenders the matched route but does not wrap the render in a try/catch and never fallsback to
getCustom500Route(...). The thrown error propagates out of the Hono middleware, so Hono'sdefault
onErrorreturnsInternal Server Error.The standard app pipeline catches the render error and serves the error page
(
packages/astro/src/core/app/base.ts/core/routing/handler.ts→renderError({ status: 500, ... }), which resolvesgetCustom500Route(...)and renders500.astro).#16907 added the symmetric
getCustom404Route(...)to the fetch pipeline (so the 404 page is nowserved for unmatched routes); the 500 counterpart for render-time errors is still missing.
Link to Minimal Reproducible Example
https://github.com/iseraph-dev/astro-hono-500-repro
Participation