solidjs/solid · warning

Cannot mutate a Store directly

Error message

Cannot mutate a Store directly

What it means

Store objects are wrapped in a Proxy whose set trap rejects direct assignment: state.field = value (in dev) warns 'Cannot mutate a Store directly'. Stores are intentionally immutable from the outside; all mutations must go through the setter returned by createStore so Solid can track and batch changes. The trap returns true so the assignment is swallowed, not applied.

Source

Thrown at packages/solid/store/src/store.ts:214

    return isWrappable(value) ? wrap(value) : value;
  },

  has(target, property) {
    if (
      property === $RAW ||
      property === $PROXY ||
      property === $TRACK ||
      property === $NODE ||
      property === $HAS ||
      property === "__proto__"
    )
      return true;
    getListener() && getNode(getNodes(target, $HAS), property)();
    return property in target;
  },

  set() {
    if (IS_DEV) console.warn("Cannot mutate a Store directly");
    return true;
  },

  deleteProperty() {
    if (IS_DEV) console.warn("Cannot mutate a Store directly");
    return true;
  },

  ownKeys: ownKeys,

  getOwnPropertyDescriptor: proxyDescriptor
};

export function setProperty(
  state: StoreNode,
  property: PropertyKey,
  value: any,
  deleting: boolean = false

View on GitHub (pinned to f47845f9cc)

Solutions

  1. Replace direct assignments with the setter: setStore('user', newUser)
  2. For arrays use setStore('items', produce(list => list.push(x))) from solid-js/store
  3. Wrap external mutators with produce/reconcile so mutation happens on the draft

Example fix

// before
const [state, setState] = createStore({ user: null });
state.user = { name: 'Ann' }; // warns, does nothing

// after
setState('user', { name: 'Ann' });
// or
setState(produce(s => { s.user = { name: 'Ann' }; }));
Defensive patterns

Strategy: validation

Validate before calling

const [state, setState] = createStore(initial);
// route all writes through setState:
function updateUser(u: User) { setState('user', u); } // not state.user = u

Type guard

import { isProxy } from 'solid-js/store';
// treat any store proxy as read-only; assert before mutating
if (isProxy(target)) throw new Error('use the store setter, not assignment');

Prevention

When it happens

Trigger: store.user = newUser, store.items.push(x), or store.items[i] = y executed directly on the store proxy instead of setStore('user', newUser) / setStore('items', i, y).

Common situations: Porting Vue/Svelte/MobX-style mutable code; passing the raw store into third-party libs that mutate their argument; refactor where a setter was accidentally replaced with assignment.

Related errors


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