Skip to content

Custom 500.astro not rendered for render-time errors under experimental.advancedRouting + astro/hono pages() #16952

@iseraph-dev

Description

@iseraph-dev

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 404my custom 404 404my custom 404
GET /boom 500Internal Server Error 500my 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

  • I am willing to submit a PR to fix this issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    - P3: minor bugAn edge case that only affects very specific usage (priority)pkg: astroRelated to the core `astro` package (scope)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions