diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js
index 4f655a3695..fd6bbdf5b4 100644
--- a/packages/svelte/src/internal/client/dom/blocks/boundary.js
+++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js
@@ -1,14 +1,8 @@
/** @import { Effect, Source, TemplateNode, } from '#client' */
-import {
- BOUNDARY_EFFECT,
- DIRTY,
- EFFECT_PRESERVED,
- EFFECT_TRANSPARENT,
- MAYBE_DIRTY
-} from '#client/constants';
+import { BOUNDARY_EFFECT, EFFECT_PRESERVED, EFFECT_TRANSPARENT } from '#client/constants';
import { HYDRATION_START_ELSE, HYDRATION_START_FAILED } from '../../../../constants.js';
import { component_context, set_component_context } from '../../context.js';
-import { handle_error, invoke_error_boundary } from '../../error-handling.js';
+import { invoke_error_boundary } from '../../error-handling.js';
import {
block,
branch,
@@ -271,13 +265,31 @@ export class Boundary {
queue_micro_task(() => {
var fragment = (this.#offscreen_fragment = document.createDocumentFragment());
var anchor = create_text();
+ var handled = false;
fragment.append(anchor);
this.#main_effect = this.#run(() => {
- return branch(() => this.#children(anchor));
+ try {
+ return branch(() => this.#children(anchor));
+ } catch (error) {
+ try {
+ this.error(error);
+ handled = true;
+ } catch (error) {
+ invoke_error_boundary(error, this.#effect.parent);
+ }
+
+ return null;
+ }
});
+ if (this.#main_effect === null) {
+ this.#offscreen_fragment = null;
+ if (handled) this.#resolve(/** @type {Batch} */ (current_batch));
+ return;
+ }
+
if (this.#pending_count === 0) {
this.#anchor.before(fragment);
this.#offscreen_fragment = null;
@@ -362,9 +374,6 @@ export class Boundary {
try {
Batch.ensure();
return fn();
- } catch (e) {
- handle_error(e);
- return null;
} finally {
set_active_effect(previous_effect);
set_active_reaction(previous_reaction);
diff --git a/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/Child.svelte
new file mode 100644
index 0000000000..a49033a8cc
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/Child.svelte
@@ -0,0 +1,7 @@
+
diff --git a/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/_config.js b/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/_config.js
new file mode 100644
index 0000000000..29e470e46f
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/_config.js
@@ -0,0 +1,14 @@
+import { tick } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ mode: ['hydrate'],
+ server_props: { environment: 'server' },
+ props: { environment: 'client' },
+ ssrHtml: 'loading inner loading nested',
+
+ async test({ assert, target }) {
+ await tick();
+ assert.htmlEqual(target.innerHTML, 'inner failed: oops outer failed: oops');
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/main.svelte
new file mode 100644
index 0000000000..16a54630d0
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-error-boundary-5/main.svelte
@@ -0,0 +1,24 @@
+
+
+
+
+ {await new Promise(() => {})}
+
+ {#snippet pending()}loading inner{/snippet}
+ {#snippet failed(error)}inner failed: {error.message}{/snippet}
+
+
+
+
+
+ {await new Promise(() => {})}
+
+ {#snippet pending()}loading nested{/snippet}
+
+
+ {#snippet failed(error)}outer failed: {error.message}{/snippet}
+