{"record":{"id":"d87ddbedcfb2cd5c","repo":"solidjs/solid","slug":"dispose-method-must-be-an-explicit-argument-to-cre","errorCode":null,"errorMessage":"Dispose method must be an explicit argument to createRoot function","messagePattern":"Dispose method must be an explicit argument to createRoot function","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/solid/src/reactive/signal.ts","lineNumber":169,"sourceCode":"  const listener = Listener,\n    owner = Owner,\n    unowned = fn.length === 0,\n    current = detachedOwner === undefined ? owner : detachedOwner,\n    root: Owner = unowned\n      ? IS_DEV\n        ? { owned: null, cleanups: null, context: null, owner: null }\n        : UNOWNED\n      : {\n          owned: null,\n          cleanups: null,\n          context: current ? current.context : null,\n          owner: current\n        },\n    updateFn = unowned\n      ? IS_DEV\n        ? () =>\n            fn(() => {\n              throw new Error(\"Dispose method must be an explicit argument to createRoot function\");\n            })\n        : fn\n      : () => fn(() => untrack(() => cleanNode(root)));\n\n  if (IS_DEV) DevHooks.afterCreateOwner && DevHooks.afterCreateOwner(root);\n\n  Owner = root;\n  Listener = null;\n\n  try {\n    return runUpdates(updateFn as () => T, true)!;\n  } finally {\n    Listener = listener;\n    Owner = owner;\n  }\n}\n\nexport type Accessor<T> = () => T;","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/solidjs/solid/blob/f47845f9cc16ecbb316aa6560c7161f45af9a3d8/packages/solid/src/reactive/signal.ts#L151-L187","documentation":"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.","triggerScenarios":"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.","commonSituations":"Setting up module-scope state or web-component internals without an owner; upgrading Solid versions where disposal semantics changed; test setup calling dispose manually.","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"],"exampleFix":"// before\ncreateRoot((dispose) => {\n  createEffect(() => console.log(state()));\n  setTimeout(dispose, 1000); // throws in dev\n});\n\n// after\nconst disposer = () => { /* cleanup */ };\ncreateRoot((dispose) => {\n  createEffect(() => console.log(state()));\n  // don't call dispose; cleanup handled by disposer\n}, disposer);","handlingStrategy":"validation","validationCode":"let owner: Owner | null = null;\ncreateRoot((dispose) => {\n  owner = getOwner();\n  // store dispose only if you provided your own disposer (2nd arg)\n}, () => { /* my dispose */ });","typeGuard":null,"tryCatchPattern":"try { dispose(); } catch (e) { if (/explicit argument/.test(String(e))) { /* unowned root: no-op intended */ } else throw e; }","preventionTips":["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"],"tags":["solid","createroot","dispose","owner","dev-only"],"backgroundTag":"unowned-reactive-dispose","analyzedSha":"f47845f9cc16ecbb316aa6560c7161f45af9a3d8","analyzedAt":"2026-08-27T05:39:24.283Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}