diff --git a/.changeset/shaggy-ghosts-decide.md b/.changeset/shaggy-ghosts-decide.md
new file mode 100644
index 000000000000..b7cb1243ecdc
--- /dev/null
+++ b/.changeset/shaggy-ghosts-decide.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+fix: fail prerendering when remote function fails
diff --git a/packages/kit/src/runtime/server/remote.js b/packages/kit/src/runtime/server/remote.js
index d2cd2f192d18..e4d199dc3f27 100644
--- a/packages/kit/src/runtime/server/remote.js
+++ b/packages/kit/src/runtime/server/remote.js
@@ -176,13 +176,19 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
});
}
+ const status =
+ error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500;
+
return json(
/** @type {RemoteFunctionResponse} */ ({
type: 'error',
error: await handle_error_and_jsonify(event, state, options, error),
- status: error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500
+ status
}),
{
+ // By setting a non-200 during prerendering we fail the prerender process (unless handleHttpError handles it).
+ // Errors at runtime will be passed to the client and are handled there
+ status: state.prerendering ? status : undefined,
headers: {
'cache-control': 'private, no-store'
}
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/package.json b/packages/kit/test/build-errors/apps/prerender-remote-function-error/package.json
new file mode 100644
index 000000000000..cf1d0aa90198
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "prerenderable-remote-function-error",
+ "private": true,
+ "version": "0.0.1",
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "prepare": "svelte-kit sync",
+ "check": "svelte-kit sync && tsc && svelte-check"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "workspace:^",
+ "@sveltejs/kit": "workspace:^",
+ "@sveltejs/vite-plugin-svelte": "catalog:",
+ "svelte": "^5.38.5",
+ "svelte-check": "^4.1.1",
+ "typescript": "^5.5.4",
+ "vite": "catalog:"
+ },
+ "type": "module"
+}
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/app.html b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/app.html
new file mode 100644
index 000000000000..866ddd01e176
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/app.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/+layout.js b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/+layout.js
new file mode 100644
index 000000000000..189f71e2e1b3
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/+layout.js
@@ -0,0 +1 @@
+export const prerender = true;
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/+page.svelte b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/+page.svelte
new file mode 100644
index 000000000000..25e7015aefb5
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/+page.svelte
@@ -0,0 +1,7 @@
+
+
+{#await throws() then value}
+ {value}
+{/await}
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/data.remote.ts b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/data.remote.ts
new file mode 100644
index 000000000000..23270e9ac3d7
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/src/routes/data.remote.ts
@@ -0,0 +1,5 @@
+import { prerender } from '$app/server';
+
+export const throws = prerender(() => {
+ throw new Error('remote function blew up');
+});
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/static/favicon.png b/packages/kit/test/build-errors/apps/prerender-remote-function-error/static/favicon.png
new file mode 100644
index 000000000000..825b9e65af7c
Binary files /dev/null and b/packages/kit/test/build-errors/apps/prerender-remote-function-error/static/favicon.png differ
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/svelte.config.js b/packages/kit/test/build-errors/apps/prerender-remote-function-error/svelte.config.js
new file mode 100644
index 000000000000..f9e8b0b2b482
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/svelte.config.js
@@ -0,0 +1,14 @@
+import adapter from '../../../../../adapter-auto/index.js';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ kit: {
+ adapter: adapter(),
+
+ experimental: {
+ remoteFunctions: true
+ }
+ }
+};
+
+export default config;
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/tsconfig.json b/packages/kit/test/build-errors/apps/prerender-remote-function-error/tsconfig.json
new file mode 100644
index 000000000000..b1096bf168cd
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "noEmit": true
+ },
+ "extends": "./.svelte-kit/tsconfig.json"
+}
diff --git a/packages/kit/test/build-errors/apps/prerender-remote-function-error/vite.config.js b/packages/kit/test/build-errors/apps/prerender-remote-function-error/vite.config.js
new file mode 100644
index 000000000000..3f12d3677ea6
--- /dev/null
+++ b/packages/kit/test/build-errors/apps/prerender-remote-function-error/vite.config.js
@@ -0,0 +1,23 @@
+import * as path from 'node:path';
+import { sveltekit } from '@sveltejs/kit/vite';
+
+/** @type {import('vite').UserConfig} */
+const config = {
+ build: {
+ minify: false
+ },
+
+ clearScreen: false,
+
+ logLevel: 'silent',
+
+ plugins: [sveltekit()],
+
+ server: {
+ fs: {
+ allow: [path.resolve('../../../../src')]
+ }
+ }
+};
+
+export default config;
diff --git a/packages/kit/test/build-errors/prerender.spec.js b/packages/kit/test/build-errors/prerender.spec.js
index 0bda6a070781..903d2491e858 100644
--- a/packages/kit/test/build-errors/prerender.spec.js
+++ b/packages/kit/test/build-errors/prerender.spec.js
@@ -29,3 +29,15 @@ test('entry generators should match their own route', { timeout }, () => {
`Error: The entries export from /[slug]/[notSpecific] generated entry /whatever/specific, which was matched by /[slug]/specific - see the \`handleEntryGeneratorMismatch\` option in https://svelte.dev/docs/kit/configuration#prerender for more info.${EOL}To suppress or handle this error, implement \`handleEntryGeneratorMismatch\` in https://svelte.dev/docs/kit/configuration#prerender`
);
});
+
+test('an error in a `prerender` function should fail the build', { timeout }, () => {
+ assert.throws(
+ () =>
+ execSync('pnpm build', {
+ cwd: path.join(process.cwd(), 'apps/prerender-remote-function-error'),
+ stdio: 'pipe',
+ timeout
+ }),
+ /remote function blew up/
+ );
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a97c77ecc4bb..7741f57fcb27 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -816,6 +816,30 @@ importers:
specifier: 'catalog:'
version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)
+ packages/kit/test/build-errors/apps/prerender-remote-function-error:
+ devDependencies:
+ '@sveltejs/adapter-auto':
+ specifier: workspace:^
+ version: link:../../../../../adapter-auto
+ '@sveltejs/kit':
+ specifier: workspace:^
+ version: link:../../../..
+ '@sveltejs/vite-plugin-svelte':
+ specifier: 'catalog:'
+ version: 6.0.0-next.3(svelte@5.38.5)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))
+ svelte:
+ specifier: ^5.38.5
+ version: 5.38.5
+ svelte-check:
+ specifier: ^4.1.1
+ version: 4.1.1(picomatch@4.0.3)(svelte@5.38.5)(typescript@5.8.3)
+ typescript:
+ specifier: ^5.5.4
+ version: 5.8.3
+ vite:
+ specifier: 'catalog:'
+ version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)
+
packages/kit/test/build-errors/apps/prerenderable-incorrect-fragment:
devDependencies:
'@sveltejs/adapter-auto':