Skip to content

Preserve deferred 406 responses in Nuxt and SolidStart #1278

Description

@dahlia

@fedify/nuxt and @fedify/solidstart defer Fedify's 406 Not Acceptable response so the application can serve another representation. Both can lose that response and send 404 when the application has no representation to serve.

Nuxt

The middleware records a deferred 406 in the H3 event context, and the plugin tries to restore it in Nitro's beforeResponse hook. On a route miss, Nitro's default error handler sends the 404 directly. The hook is never called, so the deferred response is lost.

To reproduce, use createFedifyMiddleware() and the Fedify plugin with a preemptive H3 router and Nitro's default error handler. Make Fedify reject /users/alice through onNotAcceptable, leave that path unmatched in the router, and request it with Accept: image/png. The response is 404 instead of 406, and the beforeResponse hook does not run.

The plugin also skips the fallback whenever event.context.matchedRoute is set. A catch-all renderer that returns 404 therefore also produces 404 instead of 406. A fix needs to distinguish a renderer's missing-page result from an application route's deliberate 404.

SolidStart

onBeforeResponse() checks event.response.status, then removes the stored 406. When a handler returns a Web Response, SolidStart calls the hook before H3 applies that response's status. A returned Response with status 404 can therefore look like status 200 to the hook, which discards the fallback.

With fedifyMiddleware() installed, register a Fedify actor dispatcher for /users/{identifier} and make the application handler return:

return new Response("No HTML representation", { status: 404 });

Request /users/alice with Accept: image/png. The final response is 404 instead of 406. Returning no response or throwing a 404 also loses the fallback in the tested pipeline. Setting the event's response status to 404 before returning a body does produce the expected 406, so the result depends on how the handler expresses the same status.

Affected branches and verification

The oldest affected 2.x branch for both packages is 2.2-maintenance, verified at 421e819. Neither package exists on 2.0-maintenance or 2.1-maintenance. The failures also reproduce on the fetched tips of 2.3-maintenance and 2.4-maintenance.

The reproductions ran unchanged adapter sources, with Federation.fetch() selecting onNotAcceptable to isolate the fallback. Nuxt's runtime middleware and plugin were tested with H3 1.15.3 and Nitro 2.13.3's default error handler. SolidStart was tested through its actual createMiddleware() wrapper in version 1.3.2. The lifecycle reproductions showed the failures under Bun 1.2.22; the Nuxt error path was also reproduced under Deno 2.9.7. The host was Fedora Linux 44 (x86_64). Full Nuxt and SolidStart applications were not built.

The regression coverage should include the route-miss error path and a returned Response(404), while preserving successful application responses. The SolidStart handler tests associated with #873 set the event's status directly and do not cover the returned-response timing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Fields

Priority

None yet

Effort

None yet

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions