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 = falseView on GitHub (pinned to f47845f9cc)
Solutions
- Replace direct assignments with the setter: setStore('user', newUser)
- For arrays use setStore('items', produce(list => list.push(x))) from solid-js/store
- 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
- Never assign or call mutators on store objects; always use the setter
- Use produce for imperative edits on drafts
- Hand external libraries copies (spread/structuredClone) rather than the store proxy
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
- Refusing to set "__proto__" on a store.
- Refusing to traverse unsafe key "${part}" on a store.
- Unexpected type ${typeof unwrappedStore} received when initi
- Unexpected type ${typeof unwrappedStore} received when initi
- error handlers created outside a `createRoot` or `render` wi
AI-assisted analysis of solidjs/solid@f47845f9cc (2026-08-27).
Data as JSON: /api/errors/2767b4f8c7e45eaf.
Report an issue: GitHub.