solidjs/solid · error
Attempting to access a stale value from <${name}> that could
Error message
Attempting to access a stale value from <${name}> that could possibly be undefined. This may occur because you are reading the accessor returned from the component at a time where it has already been unmounted. We recommend cleaning up any stale timers or async, or reading from the initial condition. What it means
In non-keyed <Show>, the child receives an accessor rather than a value. If Show's condition flips or the component unmounts while that accessor is read (e.g. inside an async callback or stray timer), Solid throws the narrowedError('Show') to reveal the read-after-unmount. The message recommends cleaning up stale async work or reading only while mounted.
Source
Thrown at packages/solid/src/render/flow.ts:137
? {
equals: (a, b) => !a === !b,
name: "condition"
}
: { equals: (a, b) => !a === !b }
);
return createMemo(
() => {
const c = condition();
if (c) {
const child = props.children;
const fn = typeof child === "function" && child.length > 0;
return fn
? untrack(() =>
(child as any)(
keyed
? (c as T)
: () => {
if (!untrack(condition)) throw narrowedError("Show");
return conditionValue();
}
)
)
: child;
}
return props.fallback;
},
undefined,
IS_DEV ? { name: "value" } : undefined
) as unknown as JSX.Element;
}
type EvalConditions = readonly [number, Accessor<unknown>, MatchProps<unknown>];
/**
* Switches between content based on mutually exclusive conditions
* ```typescriptView on GitHub (pinned to f47845f9cc)
Solutions
- Capture the value, not the accessor: use {(v) => <Child value={v()}>} rendered immediately
- Clean up async work with onCleanup so no reads happen after unmount
- Switch to keyed mode <Show when={x} keyed> if the child genuinely needs to hold the value across time
Example fix
// before
<Show when={user()}>
{(user) => {
setTimeout(() => api.track(user()), 5000); // accessor read after flip
return <Profile user={user()} />;
}}
</Show>
// after
<Show when={user()} keyed>
{(u) => {
setTimeout(() => api.track(u), 5000); // value captured
return <Profile user={u} />;
}}
</Show> Defensive patterns
Strategy: validation
Validate before calling
// capture the value immediately; never retain the accessor
<Show when={user()} keyed>
{(u) => {
onCleanup(() => cancelPending());
return <Profile user={u} />;
}}
</Show> Type guard
// TS-only habit: type the child as taking the value, forcing keyed
function child(u: User) { ... }
<Show when={user()} keyed>{(u) => child(u)}</Show> Try / catch
try { const v = accessor(); } catch (e) { if (/stale value/.test(String(e))) return null; /* branch no longer active */ throw e; } Prevention
- Use keyed Show when the child must retain the value past render
- Read accessors once during render; store the result
- Cancel timers/async work in onCleanup to avoid post-unmount reads
When it happens
Trigger: Non-keyed <Show when={x}>{(v) => ...}</Show> where the v accessor is captured and called later in a setTimeout, event handler, or promise callback after the condition changed; reading v outside untrack during re-evaluation.
Common situations: Passing the accessor into long-lived callbacks instead of the current value; forgetting onCleanup for async tasks; migration from keyed to non-keyed Show changing the child arg from value to accessor.
Related errors
- Expected the observer to be an object.
- Dispose method must be an explicit argument to createRoot fu
- Potential Infinite Loop Detected.
- Expected the observer to be an object.
- getContextId cannot be used under non-hydrating context
AI-assisted analysis of solidjs/solid@f47845f9cc (2026-08-27).
Data as JSON: /api/errors/c02ec7b44f3ca3d0.
Report an issue: GitHub.