Repository navigation
adapter-node 2.1.2 + kit 2.57.1: thrown SvelteKitError(413) returned to client as HTTP 500 (class-identity mismatch in bundled handler) #15755
Description
Description
When @sveltejs/adapter-node v2.1.2's pre-bundled handler creates a SvelteKitError for a 413 (e.g. via the BODY_SIZE_LIMIT chunked-body overflow path at files/handler.js:1005), the response status returned to the client is HTTP 500 with body {"type":"error","error":{"message":"Internal Error"}} instead of the expected HTTP 413.
The 413 is created and thrown — the request is correctly rejected and not buffered into memory — but it surfaces to the client with the wrong status code.
Root cause is a class identity mismatch between two separate SvelteKitError definitions:
@sveltejs/adapter-node/files/handler.js:929declares its ownclass SvelteKitError extends Errorand uses it locally to construct the 413 (line 1005). This class is module-private — adapter-node only exportshandler(line 1303).@sveltejs/kit/src/exports/internal/index.js:49exports the runtime'sclass SvelteKitError extends Error.
The two classes are structurally identical (same name, same constructor signature, same fields) but have distinct prototype-chain identities. When the error created by the adapter propagates into the runtime and reaches @sveltejs/kit/src/utils/error.js:30's get_status(error) — which calls error instanceof SvelteKitError against the runtime's class — the check returns false because the error was constructed from the adapter's class. get_status falls through to 500 and get_message falls through to 'Internal Error'.
Reproduction
-
Create a minimal SvelteKit project:
npm create svelte@latest minimal-repro # skeleton template, JS or TS cd minimal-repro npm install
-
Pin the affected versions:
npm install --save-dev @sveltejs/adapter-node@2.1.2 @sveltejs/kit@2.57.1
-
Add a POST-accepting route at
src/routes/upload/+server.js:export async function POST({ request }) { await request.text(); return new Response('ok'); }
-
Build and run:
npm run build BODY_SIZE_LIMIT=524288 node build/index.js
-
Send an oversized POST (1 MB body, 512 KB limit):
head -c 1048576 /dev/zero | curl -i -X POST --data-binary @- \ -H "Content-Type: text/plain" \ -H "Transfer-Encoding: chunked" \ http://localhost:3000/upload
Expected
HTTP/1.1 413 Payload Too Large
with a body indicating the body-size limit was exceeded.
Actual
HTTP/1.1 500 Internal Server Error
with body {\"type\":\"error\",\"error\":{\"message\":\"Internal Error\"}}.
Diagnosis (verified)
- Adapter-node does not import the runtime's
SvelteKitError; it bundles its own copy atfiles/handler.js:929. - The 413 is constructed in adapter-node's
req.on('data', ...)overflow branch (handler.js:1005) using adapter-node's bundled class. - All
instanceof SvelteKitErrorchecks live in@sveltejs/kit(src/utils/error.js:30,:37;src/runtime/server/utils.js:75,:110;src/runtime/server/remote.js:175,:208;src/runtime/server/data/index.js:114;src/runtime/app/server/remote/query.js:185). Adapter-node contains zero such checks. - The runtime's
error.js:30importsSvelteKitErrorfrom'@sveltejs/kit/internal', which resolves tosrc/exports/internal/index.js:49— a different class instance from adapter-node's bundled copy. - Additionally, neither class definition sets
this.name = 'SvelteKitError'in its constructor — so a `name`-based fallback in the runtime would also require setting the name.
Impact
Clients that distinguish 4xx (don't retry, fix your request) from 5xx (retry with backoff, server will recover) misroute oversized-POST rejections into the retry loop. Operational dashboards counting 5xx as "server health degraded" misclassify legitimate input rejections as server failures. Operators debugging "why am I getting 500s" from oversized payloads have no signal pointing at the body-size cap as the cause.
Environment
- `@sveltejs/kit`: 2.57.1
- `@sveltejs/adapter-node`: 2.1.2
- Node.js: v24.14.0
- OS: Darwin 24.6.0 arm64 (macOS)
Possible directions
(Maintainers know the codebase best — these are not prescriptions.)
- Have adapter-node import `SvelteKitError` from `@sveltejs/kit/internal` rather than bundling its own copy.
- In `@sveltejs/kit`'s `SvelteKitError` constructor, set `this.name = 'SvelteKitError'` so a `name`-based fallback is available; in `get_status` / `get_message`, add `error?.name === 'SvelteKitError'` as a backstop alongside `instanceof`.
- Adjust adapter-node's build pipeline so its `handler.js` does not pre-bundle runtime classes.
Happy to help test a fix.
Activity
elliott-with-the-longest-name-on-github commentedon Apr 28, 2026
This should be the right fix. Feel free to open a PR if you're interested in contributing; otherwise I'll get to it ASAP!
fix(adapter-node): mark @sveltejs/kit/node as external to prevent Sve…
fix: use name-based fallback for HttpError/SvelteKitError across bund…
fix: bundle entrypoints alongside app code (#16069)