diff --git a/src/runtime/internal/error/dev.ts b/src/runtime/internal/error/dev.ts index 8ddc60abcc..54eebeda5d 100644 --- a/src/runtime/internal/error/dev.ts +++ b/src/runtime/internal/error/dev.ts @@ -86,6 +86,7 @@ export async function defaultHandler( statusText: error.statusText, message: error.message, data: error.data, + ...(error.body || {}), stack: error.stack?.split("\n").map((line) => line.trim()), } : await youch.toHTML(error, { diff --git a/src/runtime/internal/error/prod.ts b/src/runtime/internal/error/prod.ts index 750be30fff..9af69471b7 100644 --- a/src/runtime/internal/error/prod.ts +++ b/src/runtime/internal/error/prod.ts @@ -62,6 +62,7 @@ export function defaultHandler( statusText: error.statusText, message: isSensitive ? "Server Error" : error.message, data: isSensitive ? undefined : error.data, + ...(isSensitive ? {} : error.body || {}), }; return { diff --git a/test/fixture/server/routes/api/error-body.ts b/test/fixture/server/routes/api/error-body.ts new file mode 100644 index 0000000000..fe215480f7 --- /dev/null +++ b/test/fixture/server/routes/api/error-body.ts @@ -0,0 +1,12 @@ +import { HTTPError } from "nitro/h3"; + +export default () => { + throw new HTTPError({ + status: 500, + message: "Custom error message", + data: { + instance: "local", + }, + body: { code: "urn:nitro:missing-error-code" }, + }); +}; diff --git a/test/tests.ts b/test/tests.ts index b608eb6ed3..a9280b76cf 100644 --- a/test/tests.ts +++ b/test/tests.ts @@ -422,6 +422,21 @@ export function testNitro( expect(data.json.error).toBe(true); }); + it("handles errors with body property", async () => { + const { status, data } = await callHandler({ + url: "/api/error-body", + headers: { + Accept: "application/json", + }, + }); + expect(status).toBe(500); + expect(data.error).toBe(true); + expect(data.message).toBe("Custom error message"); + expect(data.data).toEqual({ instance: "local" }); + // Body properties should be spread at top level + expect(data.code).toBe("urn:nitro:missing-error-code"); + }); + it.skipIf( // TODO! ctx.preset === "vercel" && ctx.nitro?.options.vercel?.entryFormat === "node" && isWindows