Repository navigation
Description
On next 3ca5262. Two sibling <Loading on={sel()}> boundaries. One reads an async memo through createErrorBoundary (used as a value-level catch), and the other reads a plain async memo keyed by the same signal. When sel changes, neither boundary shows its fallback. The old content stays on screen until both answers land, so the transition holds silently.
If you remove the error boundary, both boundaries show their fallbacks at once. A single boundary that reads through the error boundary also works (it shows loading #1). The failing combination is the error boundary read plus a sibling Loading on that is pending.
/** @jsxImportSource @solidjs/web @vitest-environment jsdom */
import { test } from "vitest";
import { Loading, createErrorBoundary, createMemo, createSignal, flush, untrack } from "solid-js";
import { render } from "../src/index.js";
const tick = async () => { for (let i = 0; i < 4; i++) { await new Promise(r => setTimeout(r, 0)); flush(); } };
for (const caught of [true, false]) test(`switch key (${caught ? "error boundary" : "plain"})`, async () => {
const asks: { key: string; res: (v: any) => void }[] = [];
const ask = (key: string) => new Promise<any>(res => asks.push({ key, res }));
const settle = async (key: string, v: any) => { asks.splice(asks.findIndex(a => a.key === key), 1)[0].res(v); await tick(); };
const c = document.body.appendChild(document.createElement("div"));
let select!: (n: number) => void;
render(() => {
const [sel, setSel] = createSignal(3); select = setSel;
const detail = createMemo(() => ask(`detail:${sel()}`));
const shown = caught ? untrack(() => createErrorBoundary(() => detail(), () => null)) : detail;
const comments = createMemo(() => ask(`comments:${sel()}`));
return <>
<Loading on={sel()} fallback={<i>loading #{sel()}</i>}><b>{(shown() as any)?.title}</b></Loading>
<Loading on={sel()} fallback={<i> loading comments</i>}><u> comments {(comments() as any[]).length}</u></Loading>
</>;
}, c);
await tick();
await settle("detail:3", { title: "Crash" }); await settle("comments:3", [1]);
select(1); await tick();
console.log(caught ? "[error boundary]" : "[plain]", c.textContent);
});Output after select(1), while detail:1 and comments:1 are in flight:
[error boundary] Crash comments 1 <- expected: loading #1 loading comments
[plain] loading #1 loading comments
Found in ReactiveScript's AI eval (round 10, desk rx-1). There, okDetail = (asked catch (e) => null) lowers to createErrorBoundary. The issue switch never showed "loading #N", and the error lines for the old issue stayed up until the new issue's answers landed. If the agent's app uses an errored region instead of the catch expression, it shows the fallback at once.
Activity
test(web): import createErrorBoundary from solid-js/internal in the #…
fix(signals): a pending error-boundary output read only behind fallba…
ryansolid commentedon Nov 3, 2026
Fixed on
nextby #4639 (6e569c7); it ships in the next RC.Generated by Claude Code