Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conditional promise rendering breaks hydration #13665

Open
Rican7 opened this issue Apr 2, 2025 · 0 comments
Open

Conditional promise rendering breaks hydration #13665

Rican7 opened this issue Apr 2, 2025 · 0 comments
Labels

Comments

@Rican7
Copy link

Rican7 commented Apr 2, 2025

Describe the bug

This bug took me hours to understand and realize a minimum reproduction for, but it's currently blocking my company site from fully functioning.

This issue is seemingly related to #11057 (and maybe #13527/#13631), but it's not due to just "malformed HTML".

What happens is that hydration fails, with a JS error/crash, after the server-side rendered page has shown and client-side rendering has begun to take over, when combining 3 specific things:

  1. A page has an {#await} block
  2. The await block awaits data that is conditionally a promise or not (in loader: return { key: browser ? promiseVal : val };)
  3. The {#await} block and it's {:then} block BOTH contain a component. (This one took a long time to realize)

This will all make much more sense in the reproduction section, but yea, this ends up as a pretty bad break, breaking the whole page, showing nothing but an empty background as the whole app's %sveltekit.body% section is wiped out, with an error in the browser's console.

The specific error is different depending on the contents of your await block, but for example the minimum reproduction shows: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'substring'). My production app, however, shows: Uncaught (in promise) DOMException: Node.appendChild: Cannot add children to a Comment.

Due to the nature of the bug being due to hydration, though, it only occurs on fresh-page loads or browser refreshes of the page. If you navigate to a page that meets these repro requirements, and the app has already been initialized/hydrated, then no error occurs.

Reproduction

For full context, here's a full minimum reproduction on StackBlitz:
https://stackblitz.com/edit/sveltekit-conditional-promise-rendering-bug?file=src%2Froutes%2F%2Bpage.svelte

Otherwise, the important bits are:

+page.js

import { browser } from '$app/environment';

const picSrc = '/favicon.png';
const waitAndReturn = (toReturn) => {
  return async () => {
    await new Promise((resolve) => setTimeout(resolve, 2000));

    return toReturn;
  };
};

/** @type {import('./$types').PageLoad} */
export async function load({ fetch }) {
  return {
    picUrl: browser ? waitAndReturn(picSrc)() : picSrc,
  };
}

+page.svelte

<script>
	import { browser } from '$app/environment';
	import Counter from './Counter.svelte'; // Can seemingly be any component?

	/** @type {import('./$types').PageProps} */
	let { data } = $props();
</script>

<section>
	{#await data.picUrl}
		<Counter />
		{#if browser}
			Loading...
		{/if}
	{:then picUrl}
		<Counter />
		<img src={picUrl} alt="pic" />
	{:catch}
		Error fetching data.
	{/await}
</section>

Logs

(Shortened. Expand for full log...)


[vite] connecting...
client:866 [vite] connected.
chunk-UDIWMOKF.js?v=68c9c188:483 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'substring')
in +page.svelte
in +layout.svelte
in root.svelte

at update_branch (chunk-UDIWMOKF.js?v=68c9c188:483:41)


[vite] connecting...
client:866 [vite] connected.
chunk-UDIWMOKF.js?v=68c9c188:483 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'substring')

	in +page.svelte
	in +layout.svelte
	in root.svelte

    at update_branch (chunk-UDIWMOKF.js?v=68c9c188:483:41)
    at set_branch (chunk-UDIWMOKF.js?v=68c9c188:467:5)
    at +page.svelte:12:15
    at chunk-UDIWMOKF.js?v=68c9c188:527:5
    at update_reaction (chunk-WZ7WN4W3.js?v=68c9c188:1839:23)
    at update_effect (chunk-WZ7WN4W3.js?v=68c9c188:1958:21)
    at create_effect (chunk-WZ7WN4W3.js?v=68c9c188:2358:7)
    at block (chunk-WZ7WN4W3.js?v=68c9c188:2500:10)
    at Module.if_block (chunk-UDIWMOKF.js?v=68c9c188:525:3)
    at +page.svelte:10:21
update_branch @ chunk-UDIWMOKF.js?v=68c9c188:483
set_branch @ chunk-UDIWMOKF.js?v=68c9c188:467
(anonymous) @ +page.svelte:12
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:527
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
if_block @ chunk-UDIWMOKF.js?v=68c9c188:525
(anonymous) @ +page.svelte:10
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:436
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:436
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
await_block @ chunk-UDIWMOKF.js?v=68c9c188:414
_page @ +page.svelte:3
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:288
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:282
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
wrapper @ chunk-UDIWMOKF.js?v=68c9c188:275
(anonymous) @ root.svelte:48
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
component @ chunk-UDIWMOKF.js?v=68c9c188:1149
(anonymous) @ root.svelte:48
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1108
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1096
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1094
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
snippet @ chunk-UDIWMOKF.js?v=68c9c188:1085
_layout @ +layout.svelte:2
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:288
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:282
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
wrapper @ chunk-UDIWMOKF.js?v=68c9c188:275
(anonymous) @ root.svelte:46
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
component @ chunk-UDIWMOKF.js?v=68c9c188:1149
consequent @ root.svelte:46
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:502
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
update_branch @ chunk-UDIWMOKF.js?v=68c9c188:502
set_branch @ chunk-UDIWMOKF.js?v=68c9c188:467
(anonymous) @ root.svelte:45
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:527
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
if_block @ chunk-UDIWMOKF.js?v=68c9c188:525
Root @ root.svelte:56
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:288
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:282
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
wrapper @ chunk-UDIWMOKF.js?v=68c9c188:275
(anonymous) @ chunk-IQNBARE7.js?v=68c9c188:570
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-IQNBARE7.js?v=68c9c188:550
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
component_root @ chunk-WZ7WN4W3.js?v=68c9c188:2433
_mount @ chunk-IQNBARE7.js?v=68c9c188:548
hydrate @ chunk-IQNBARE7.js?v=68c9c188:497
Svelte4Component @ chunk-IQNBARE7.js?v=68c9c188:743
(anonymous) @ chunk-IQNBARE7.js?v=68c9c188:700
initialize @ client.js?v=68c9c188:472
_hydrate @ client.js?v=68c9c188:2652
await in _hydrate
start @ client.js?v=68c9c188:321
await in start
(anonymous) @ (index):269
Promise.then
(anonymous) @ (index):268Understand this errorAI
chunk-WZ7WN4W3.js?v=68c9c188:2333 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'f')
    at create_effect (chunk-WZ7WN4W3.js?v=68c9c188:2333:39)
    at branch (chunk-WZ7WN4W3.js?v=68c9c188:2503:10)
    at update2 (chunk-UDIWMOKF.js?v=68c9c188:389:28)
    at chunk-UDIWMOKF.js?v=68c9c188:423:11
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2333
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
update2 @ chunk-UDIWMOKF.js?v=68c9c188:389
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:423
Promise.then
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:419
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
await_block @ chunk-UDIWMOKF.js?v=68c9c188:414
_page @ +page.svelte:3
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:288
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:282
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
wrapper @ chunk-UDIWMOKF.js?v=68c9c188:275
(anonymous) @ root.svelte:48
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
component @ chunk-UDIWMOKF.js?v=68c9c188:1149
(anonymous) @ root.svelte:48
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1108
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1096
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1094
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
snippet @ chunk-UDIWMOKF.js?v=68c9c188:1085
_layout @ +layout.svelte:2
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:288
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:282
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
wrapper @ chunk-UDIWMOKF.js?v=68c9c188:275
(anonymous) @ root.svelte:46
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:1156
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
component @ chunk-UDIWMOKF.js?v=68c9c188:1149
consequent @ root.svelte:46
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:502
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
update_branch @ chunk-UDIWMOKF.js?v=68c9c188:502
set_branch @ chunk-UDIWMOKF.js?v=68c9c188:467
(anonymous) @ root.svelte:45
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:527
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
if_block @ chunk-UDIWMOKF.js?v=68c9c188:525
Root @ root.svelte:56
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:288
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-UDIWMOKF.js?v=68c9c188:282
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
block @ chunk-WZ7WN4W3.js?v=68c9c188:2500
wrapper @ chunk-UDIWMOKF.js?v=68c9c188:275
(anonymous) @ chunk-IQNBARE7.js?v=68c9c188:570
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
branch @ chunk-WZ7WN4W3.js?v=68c9c188:2503
(anonymous) @ chunk-IQNBARE7.js?v=68c9c188:550
update_reaction @ chunk-WZ7WN4W3.js?v=68c9c188:1839
update_effect @ chunk-WZ7WN4W3.js?v=68c9c188:1958
create_effect @ chunk-WZ7WN4W3.js?v=68c9c188:2358
component_root @ chunk-WZ7WN4W3.js?v=68c9c188:2433
_mount @ chunk-IQNBARE7.js?v=68c9c188:548
hydrate @ chunk-IQNBARE7.js?v=68c9c188:497
Svelte4Component @ chunk-IQNBARE7.js?v=68c9c188:743
(anonymous) @ chunk-IQNBARE7.js?v=68c9c188:700
initialize @ client.js?v=68c9c188:472
_hydrate @ client.js?v=68c9c188:2652
await in _hydrate
start @ client.js?v=68c9c188:321
await in start
(anonymous) @ (index):269
Promise.then
(anonymous) @ (index):268

System Info

System:
    OS: Linux 4.4 Ubuntu 22.04.5 LTS 22.04.5 LTS (Jammy Jellyfish)
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 8.11 GB / 31.74 GB
    Container: Yes
    Shell: 5.1.16 - /usr/bin/bash
  Binaries:
    Node: 22.14.0 - ~/.nvm/versions/node/v22.14.0/bin/node
    Yarn: 1.22.22 - ~/.nvm/versions/node/v22.14.0/bin/yarn
    npm: 11.2.0 - ~/.nvm/versions/node/v22.14.0/bin/npm
    pnpm: 9.15.4 - ~/.nvm/versions/node/v22.14.0/bin/pnpm
  npmPackages:
    @sveltejs/adapter-auto: ^6.0.0 => 6.0.0
    @sveltejs/adapter-node: ^5.2.12 => 5.2.12
    @sveltejs/kit: ^2.20.3 => 2.20.3
    @sveltejs/vite-plugin-svelte: ^5.0.3 => 5.0.3
    svelte: ^5.25.6 => 5.25.6
    vite: ^6.2.4 => 6.2.4

Severity

serious, but I can work around it

Additional Information

Removing the conditional promise loading (if (browser)) fixes the issue, but that's not a workable solution for my company's application, as we rely on the server-side rendering for SEO and noscript fallback, but need the client-side rendering for the app-like client-side instant navigation and loading UIs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants