solidjs/solid · warning

computations created outside a `createRoot` or `render` will

Error message

computations created outside a `createRoot` or `render` will never be disposed

What it means

When a computation (createEffect/createMemo/createComputed etc.) is created with Owner === null, it is attached to the global UNOWNED graph and will never be disposed automatically, leaking memory and updates. Solid logs this dev-only warning; in production the computation still runs, just unowned.

Source

Thrown at packages/solid/src/reactive/signal.ts:1469

    updatedAt: null,
    owned: null,
    sources: null,
    sourceSlots: null,
    cleanups: null,
    value: init,
    owner: Owner,
    context: Owner ? Owner.context : null,
    pure
  };

  if (Transition && Transition.running) {
    c.state = 0;
    c.tState = state;
  }

  if (Owner === null)
    IS_DEV &&
      console.warn(
        "computations created outside a `createRoot` or `render` will never be disposed"
      );
  else if (Owner !== UNOWNED) {
    if (Transition && Transition.running && (Owner as Memo<Init, Next>).pure) {
      if (!(Owner as Memo<Init, Next>).tOwned) (Owner as Memo<Init, Next>).tOwned = [c];
      else (Owner as Memo<Init, Next>).tOwned!.push(c);
    } else {
      if (!Owner.owned) Owner.owned = [c];
      else Owner.owned.push(c);
    }
  }

  if (IS_DEV && options && options.name) c.name = options.name;

  if (ExternalSourceConfig && c.fn) {
    const sourceFn = c.fn;
    const [track, trigger] = createSignal<void>(undefined, { equals: false });
    const ordinary = ExternalSourceConfig.factory(sourceFn, trigger);

View on GitHub (pinned to f47845f9cc)

Solutions

  1. Wrap the reactive setup in createRoot(dispose => ...) so computations get an owner
  2. Move the effect inside a component rendered by render(), which creates its own root
  3. For intentionally global effects, accept the warning in dev or use a dedicated root island you dispose on shutdown

Example fix

// before
createEffect(() => document.title = title()); // module scope: never disposed

// after
createRoot((dispose) => {
  createEffect(() => (document.title = title()));
  // call dispose() when the app tears down
});
Defensive patterns

Strategy: validation

Validate before calling

import { getOwner, createRoot } from 'solid-js';
export function withRoot<T>(fn: () => T): T {
  return getOwner() ? fn() : createRoot((dispose) => { const r = fn(); queueMicrotask(dispose); return r; });
}

Type guard

import { getOwner } from 'solid-js';
const hasOwner = (): boolean => getOwner() !== null;

Prevention

When it happens

Trigger: Calling createEffect/createComputed/createMemo at module scope or outside render()/createRoot; standalone reactive setups in scripts, workers, or top-level await contexts.

Common situations: Bootstrapping reactive logic at app entry before render; extracting effects into non-component utilities; SSR code paths creating effects outside roots.

Related errors


AI-assisted analysis of solidjs/solid@f47845f9cc (2026-08-27). Data as JSON: /api/errors/edb663e72b3b47e0. Report an issue: GitHub.