{"record":{"id":"9303bf8955e3efc0","repo":"mobxjs/mobx","slug":"mobx-side-effects-like-changing-state-are-not-al","errorCode":null,"errorMessage":"[MobX] Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, a computed value or the render function of a React component? You can wrap side effects in 'runInAction' (or decorate functions with 'action') if needed. Tried to modify: ${atom.name_}","messagePattern":"\\[MobX\\] Side effects like changing state are not allowed at this point\\. Are you trying to modify state from, for example, a computed value or the render function of a React component\\? You can wrap side effects in 'runInAction' \\(or decorate functions with 'action'\\) if needed\\. Tried to modify: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/mobx/src/core/derivation.ts","lineNumber":143,"sourceCode":"        }\n    }\n}\n\nexport function isComputingDerivation() {\n    return globalState.trackingDerivation !== null // filter out actions inside computations\n}\n\nexport function checkIfStateModificationsAreAllowed(atom: IAtom) {\n    if (!__DEV__) {\n        return\n    }\n    const hasObservers = !!atom.observers_ && atom.observers_.size > 0\n    // Should not be possible to change observed state outside strict mode, except during initialization, see #563\n    if (\n        !globalState.allowStateChanges &&\n        (hasObservers || globalState.enforceActions === \"always\")\n    ) {\n        console.warn(\n            \"[MobX] \" +\n                (globalState.enforceActions\n                    ? \"Since strict-mode is enabled, changing (observed) observable values without using an action is not allowed. Tried to modify: \"\n                    : \"Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, a computed value or the render function of a React component? You can wrap side effects in 'runInAction' (or decorate functions with 'action') if needed. Tried to modify: \") +\n                atom.name_\n        )\n    }\n}\n\nexport function checkIfStateReadsAreAllowed(observable: IObservable) {\n    if (__DEV__ && !globalState.allowStateReads && globalState.observableRequiresReaction) {\n        console.warn(\n            `[mobx] Observable '${observable.name_}' being read outside a reactive context.`\n        )\n    }\n}\n\n/**","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/mobxjs/mobx/blob/01211a698b64ea94de8e5f276ff8235fcf8ddf96/packages/mobx/src/core/derivation.ts#L125-L161","documentation":"Same checkIfStateModificationsAreAllowed guard, but this variant of the message is emitted when globalState.enforceActions is falsy while the modification still happens where state changes are disallowed — typically inside a computed value or during a React render. MobX blocks side effects during derivation/rendering because changing observed state there breaks the reactive transaction and can cause inconsistent renders.","triggerScenarios":"Writing to an observable from inside a computed() getter, an observer component's render body, or a reaction's trace phase, when allowStateChanges is false but enforceActions is not 'always' (message takes the 'side effects' branch because globalState.enforceActions is falsy/0).","commonSituations":"Caching derived values back into a store property inside a computed getter; calling store mutators directly from JSX render code; initializing observers lazily during first render; upgrading code that relied on enforceActions defaults.","solutions":["Move the state write out of the computed/render path into an action, reaction, or event handler.","If a computed must record something, model it as a true computed (getObservableValue) instead of writing back.","Use runInAction inside an event/async callback rather than during rendering.","If the write must happen lazily, use an @observable with a setter method invoked from user code, not render."],"exampleFix":"// before\nget fullName() {\n  this.displayName = this.first + ' ' + this.last // side effect in computed\n  return this.displayName\n}\n\n// after\nget fullName() {\n  return this.first + ' ' + this.last // pure derivation\n}","handlingStrategy":"validation","validationCode":"function assertNotInRender(mutate) {\n  if (typeof window !== 'undefined' && window.__MOBX_IN_RENDER__) {\n    throw new Error('Cannot mutate state during render; defer to an action/event handler')\n  }\n  return mutate\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep computed getters pure — never assign to observables inside them.","Defer writes from render via queueMicrotask(() => runInAction(...)) only if truly unavoidable.","React to computed changes with reaction() instead of writing back in the getter."],"tags":["mobx","side-effect","computed","render","reactivity"],"backgroundTag":"mobx-side-effect-in-computed-or-render","analyzedSha":"01211a698b64ea94de8e5f276ff8235fcf8ddf96","analyzedAt":"2026-08-28T22:10:08.831Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}