Skip to content

Public request-level failure report for the server error hook (kind: "request") #3723

Closed

Description

@ryansolid

Summary

configureServerErrors promises the ambient hook hears "the failure that fails a request", but the runtime can only report failures it meets itself — inside renderToStream (kind: "render") or inside a server-function dispatch (kind: "server-function"). A failure that happens in the framework's request handler before any render exists (Start middleware, setup, the render-mode module throwing) has no site and no public way to be reported. The only funnel is reportServerError, which is solid-js/internal.

Where this bites

solidjs/solid-vite-plugin#383 (design in solidjs/solid-vite-plugin#382) adds containment at the generated Start handler edge: a thrown Response becomes the response, anything else becomes a 500 instead of rejecting out to the host (Vite overlay / plain-text 500 / e.message echoed by the example server / configureServerErrors never hearing it). To report the failure it has to:

  • import reportServerError from solid-js/internal into every production Start build (the header says "NOT public API… may change or vanish in any release");
  • read globalThis[Symbol.for("solid-js/server/errors")].hook to decide whether to console.error — duplicating failRender's fallback policy (packages/web/src/server.ts ~L2061–2069);
  • label the site { kind: "render", handling: "failed" } because ServerErrorSite.kind has nothing else. A monitor using the documented `solid.${kind}.${handling}` mechanism files middleware throws as render failures.

Proposal

Public request-level failure report on @solidjs/web/server, same policy as failRender, written once in the package that owns the slot:

// ServerErrorSite
kind: "render" | "server-function" | "request";
// handling for "request" is always "failed"; `event` always present.

export function reportRequestFailure(error: unknown, event: RequestEvent): void;
// = reportServerError(error, { kind: "request", handling: "failed", event }, null)
//   + console.error(error) iff no ambient hook (per-request hooks don't exist at this layer)

Hook return ignored, as for every handling: "failed". The once-per-error ledger already applies, so an in-process server-function failure reported as server-function/thrown that then propagates through the middleware is not reported twice.

No change to renderToStream, onError, the server-function handler, or any wire format. configureServerErrors docs updated so "the failure that fails a request" is true for the pre-render case too.

Public API

  • ServerErrorSite.kind gains "request".
  • New export reportRequestFailure(error, event) from @solidjs/web/server.

Related, found while reviewing #383 (separate issues if you want them tracked)

  • An async render failure before the shell with no boundary leaves the response pending forever (createSSRResponse.end() never resolves the head).
  • A framework-side throw after next() has already returned a rendered page cannot cancel that render's stream; it keeps running into a buffer nobody reads.

Once this ships (rc.14), #383 shrinks to one import + one call; the containment shape and its fixtures stay as written.

— Claude via Cursor

Activity

  1. everton-dgn commented on Oct 2, 2026

    @everton-dgn

    I can take this one if you haven't started on it. The shape I have in mind:

    • reportRequestFailure(error, event) exported from @solidjs/web itself, next to configureServerErrors in the server entry, with a no-op in server-mock.ts as configureServerErrors has. There's no ./server subpath in the package's exports today, and I'd rather not add one for a single function.
    • "request" added to ServerErrorSite.kind in packages/solid/src/server/signals.ts, so the PR carries a changeset for solid-js and one for @solidjs/web.
    • The same policy as failRender: reportServerError(error, { kind: "request", handling: "failed", event }, null), then console.error(error) only when no ambient hook is registered. A test pins the ledger case, where a server-function/thrown failure that then escapes the middleware isn't reported a second time.

    Once it's published, #383 drops its solid-js/internal import and calls this instead. Should I go ahead?

  2. added a commit that references this issue on Oct 4, 2026
    41fdf96
  3. ryansolid commented on Oct 4, 2026

    @ryansolid
    MemberAuthor

    Implemented in #3763 (thanks @everton-dgn), merged into next.

    • reportRequestFailure(error, event) is exported from @solidjs/web, next to configureServerErrors. It reports through the server error hook as kind: "request", handling: "failed", with the RequestEvent attached. The client build gets a no-op.
    • Each error is reported once, so an error the runtime already reported isn't heard again.
    • Synchronous first-pass render throws from renderToString and renderToStream are now reported as render/failed before they're rethrown. A framework that catches one and calls reportRequestFailure adds nothing, so "request" only labels failures outside any render.

    It ships in the next RC.

    — Claude via Cursor

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions