Repository: sveltejs/kit
Pull request #7303 (2022-10-18 12:14:58)

[fix] more informative serialization error messages
### Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it solves.
- [ ] Ideally, include a test that fails without this PR but passes with it.

### Tests
- [ ] Run the tests with `pnpm test` and lint the project with `pnpm lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpm changeset` and following the prompts. All changesets should be `patch` until SvelteKit 1.0


changeset-bot[bot]: ###  🦋  Changeset detected

Latest commit: 9fb84b399375fbeeeccf6efb08ecc5247b13a0d6

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name          | Type  |
| ------------- | ----- |
| @sveltejs/kit | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/sveltejs/kit/new/ser-error-message?filename=.changeset/young-penguins-jump.md&value=---%0A%22%40sveltejs%2Fkit%22%3A%20patch%0A---%0A%0A%5Bfix%5D%20more%20informative%20serialization%20error%20messages%0A)



Patch:
diff --git a/.changeset/serious-llamas-smoke.md b/.changeset/serious-llamas-smoke.md
new file mode 100644
index 000000000..7a33ae3e3
--- /dev/null
+++ b/.changeset/serious-llamas-smoke.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] more informative serialization error messages
diff --git a/.changeset/spotty-kangaroos-peel.md b/.changeset/spotty-kangaroos-peel.md
new file mode 100644
index 000000000..db342321a
--- /dev/null
+++ b/.changeset/spotty-kangaroos-peel.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[fix] add `$types` to includes for better DX
diff --git a/packages/kit/src/core/sync/write_tsconfig.js b/packages/kit/src/core/sync/write_tsconfig.js
index 8e3d42ebd..b97b1a084 100644
--- a/packages/kit/src/core/sync/write_tsconfig.js
+++ b/packages/kit/src/core/sync/write_tsconfig.js
@@ -46,7 +46,7 @@ export function write_tsconfig(config, cwd = process.cwd()) {
 	/** @param {string} file */
 	const config_relative = (file) => posixify(path.relative(config.outDir, file));
 
-	const include = ['ambient.d.ts', config_relative('vite.config.ts')];
+	const include = ['ambient.d.ts', './types/**/$types.d.ts', config_relative('vite.config.ts')];
 	for (const dir of [config.files.routes, config.files.lib]) {
 		const relative = project_relative(path.dirname(dir));
 		include.push(config_relative(`${relative}/**/*.js`));
diff --git a/packages/kit/src/runtime/server/data/index.js b/packages/kit/src/runtime/server/data/index.js
index 3e0ea3890..33c9a68a7 100644
--- a/packages/kit/src/runtime/server/data/index.js
+++ b/packages/kit/src/runtime/server/data/index.js
@@ -111,7 +111,7 @@ export async function render_data(event, route, options, state) {
 			nodes: nodes.slice(0, length)
 		};
 
-		return data_response(server_data);
+		return data_response(server_data, event);
 	} catch (e) {
 		const error = normalize_error(e);
 
@@ -122,10 +122,10 @@ export async function render_data(event, route, options, state) {
 				location: error.location
 			};
 
-			return data_response(server_data);
+			return data_response(server_data, event);
 		} else {
 			// TODO make it clearer that this was an unexpected error
-			return data_response(handle_error_and_jsonify(event, options, error));
+			return data_response(handle_error_and_jsonify(event, options, error), event);
 		}
 	}
 }
diff --git a/packages/kit/src/runtime/server/page/actions.js b/packages/kit/src/runtime/server/page/actions.js
index eb5b7c187..1c1d554cc 100644
--- a/packages/kit/src/runtime/server/page/actions.js
+++ b/packages/kit/src/runtime/server/page/actions.js
@@ -248,5 +248,9 @@ function check_serializability(value, id, path) {
 		}
 	}
 
-	throw new Error(`${path} returned from action in ${id} cannot be serialized as JSON`);
+	throw new Error(
+		`${path} returned from action in ${id} cannot be serialized as JSON without losing its original type` +
+			// probably the most common case, so let's give a hint
+			(value instanceof Date ? ' (Date objects are serialized as strings)' : '')
+	);
 }
diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js
index b26c4da88..7953d3301 100644
--- a/packages/kit/src/runtime/server/page/render.js
+++ b/packages/kit/src/runtime/server/page/render.js
@@ -177,7 +177,11 @@ export async function render_response({
 		// function, but it would mean passing more stuff around than we currently do
 		const error = /** @type {any} */ (e);
 		const match = /\[(\d+)\]\.data\.(.+)/.exec(error.path);
-		if (match) throw new Error(`${error.message} (data.${match[2]})`);
+		if (match) {
+			throw new Error(
+				`Data returned from \`load\` while rendering /${event.routeId} is not serializable: ${error.message} (data.${match[2]})`
+			);
+		}
 		throw error;
 	}
 
diff --git a/packages/kit/src/runtime/server/utils.js b/packages/kit/src/runtime/server/utils.js
index 08bc5437d..33ef9b7c0 100644
--- a/packages/kit/src/runtime/server/utils.js
+++ b/packages/kit/src/runtime/server/utils.js
@@ -67,8 +67,11 @@ export function allowed_methods(mod) {
 	return allowed;
 }
 
-/** @param {any} data */
-export function data_response(data) {
+/**
+ * @param {any} data
+ * @param {import('types').RequestEvent} event
+ */
+export function data_response(data, event) {
 	const headers = {
 		'content-type': 'application/json',
 		'cache-control': 'private, no-store'
@@ -79,7 +82,9 @@ export function data_response(data) {
 	} catch (e) {
 		const error = /** @type {any} */ (e);
 		const match = /\[(\d+)\]\.data\.(.+)/.exec(error.path);
-		const message = match ? `${error.message} (data.${match[2]})` : error.message;
+		const message = match
+			? `Data returned from \`load\` while rendering /${event.routeId} is not serializable: ${error.message} (data.${match[2]})`
+			: error.message;
 		return new Response(JSON.stringify(message), { headers, status: 500 });
 	}
 }


Test patch:
diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js
index 0588cdc6b..9331e7708 100644
--- a/packages/kit/test/apps/basics/test/test.js
+++ b/packages/kit/test/apps/basics/test/test.js
@@ -308,7 +308,7 @@ test.describe('Shadowed pages', () => {
 
 			expect(await page.textContent('h1')).toBe('500');
 			expect(await page.textContent('#message')).toBe(
-				'This is your custom error page saying: "Cannot stringify arbitrary non-POJOs (data.nope)"'
+				'This is your custom error page saying: "Data returned from `load` while rendering /shadowed/serialization is not serializable: Cannot stringify arbitrary non-POJOs (data.nope)"'
 			);
 		});
 	}