solidjs/solid · error · Error
Dispose method must be an explicit argument to createRoot fu
Error message
Dispose method must be an explicit argument to createRoot function
What it means
createRoot(fn) called without an owner (unowned) hands fn a dispose callback that, in dev builds, throws when invoked. Unowned roots have no owner to attach disposal to, so Solid makes the useless dispose loud instead of silently doing nothing. In production builds the dispose is simply a no-op.
Source
Thrown at packages/solid/src/reactive/signal.ts:169
const listener = Listener,
owner = Owner,
unowned = fn.length === 0,
current = detachedOwner === undefined ? owner : detachedOwner,
root: Owner = unowned
? IS_DEV
? { owned: null, cleanups: null, context: null, owner: null }
: UNOWNED
: {
owned: null,
cleanups: null,
context: current ? current.context : null,
owner: current
},
updateFn = unowned
? IS_DEV
? () =>
fn(() => {
throw new Error("Dispose method must be an explicit argument to createRoot function");
})
: fn
: () => fn(() => untrack(() => cleanNode(root)));
if (IS_DEV) DevHooks.afterCreateOwner && DevHooks.afterCreateOwner(root);
Owner = root;
Listener = null;
try {
return runUpdates(updateFn as () => T, true)!;
} finally {
Listener = listener;
Owner = owner;
}
}
export type Accessor<T> = () => T;View on GitHub (pinned to f47845f9cc)
Solutions
- Pass your own dispose as the second argument: createRoot(disposer => { ... }, myDispose)
- Or run the code inside an existing owner (e.g. inside createRoot created by render())
- Or never call the dispose callback of an unowned root and manage cleanup via onCleanup elsewhere
Example fix
// before
createRoot((dispose) => {
createEffect(() => console.log(state()));
setTimeout(dispose, 1000); // throws in dev
});
// after
const disposer = () => { /* cleanup */ };
createRoot((dispose) => {
createEffect(() => console.log(state()));
// don't call dispose; cleanup handled by disposer
}, disposer); Defensive patterns
Strategy: validation
Validate before calling
let owner: Owner | null = null;
createRoot((dispose) => {
owner = getOwner();
// store dispose only if you provided your own disposer (2nd arg)
}, () => { /* my dispose */ }); Try / catch
try { dispose(); } catch (e) { if (/explicit argument/.test(String(e))) { /* unowned root: no-op intended */ } else throw e; } Prevention
- Never call the dispose argument of an ownerless createRoot
- Pass an explicit disposer as createRoot's 2nd argument when you need custom cleanup
- Create roots inside component/render lifecycles whenever possible
When it happens
Trigger: Calling createRoot(fn) outside of any reactive owner and then invoking the dispose argument passed to fn (e.g. const [dispose] = createRoot(d => ...); dispose()). Common in top-level module code or tests without createRoot's second argument.
Common situations: Setting up module-scope state or web-component internals without an owner; upgrading Solid versions where disposal semantics changed; test setup calling dispose manually.
Related errors
- error handlers created outside a `createRoot` or `render` wi
- Unexpected type ${typeof unwrappedStore} received when initi
- Unexpected type ${typeof unwrappedStore} received when initi
- cleanups created outside a `createRoot` or `render` will nev
- computations created outside a `createRoot` or `render` will
AI-assisted analysis of solidjs/solid@f47845f9cc (2026-08-27).
Data as JSON: /api/errors/d87ddbedcfb2cd5c.
Report an issue: GitHub.