mobxjs/mobx · warning
[mobx] Observable '${observable.name_}' being read outside a
Error message
[mobx] Observable '${observable.name_}' being read outside a reactive context. What it means
checkIfStateReadsAreAllowed warns when an observable marked as requiring reaction (observableRequiresReaction enabled, or per-observable requiresObservable_) is read outside any reactive context (no active derivation). MobX enforces this so reads that should drive reactions aren't silently untracked, which would break the reaction contract.
Source
Thrown at packages/mobx/src/core/derivation.ts:155
const hasObservers = !!atom.observers_ && atom.observers_.size > 0
// Should not be possible to change observed state outside strict mode, except during initialization, see #563
if (
!globalState.allowStateChanges &&
(hasObservers || globalState.enforceActions === "always")
) {
console.warn(
"[MobX] " +
(globalState.enforceActions
? "Since strict-mode is enabled, changing (observed) observable values without using an action is not allowed. Tried to modify: "
: "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_
)
}
}
export function checkIfStateReadsAreAllowed(observable: IObservable) {
if (__DEV__ && !globalState.allowStateReads && globalState.observableRequiresReaction) {
console.warn(
`[mobx] Observable '${observable.name_}' being read outside a reactive context.`
)
}
}
/**
* Executes the provided function `f` and tracks which observables are being accessed.
* The tracking information is stored on the `derivation` object and the derivation is registered
* as observer of any of the accessed observables.
*/
export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, context: any) {
const prevAllowStateReads = __DEV__ ? allowStateReadsStart(true) : true
changeDependenciesStateTo0(derivation)
// Preallocate array; will be trimmed by bindDependencies.
derivation.newObserving_ = new Array(
// Reserve constant space for initial dependencies, dynamic space otherwise.
// See https://github.com/mobxjs/mobx/pull/3833
derivation.runId_ === 0 ? 100 : derivation.observing_.lengthView on GitHub (pinned to 01211a698b)
Solutions
- Read the value inside a reactive context: computed, reaction(), autorun(), or an observer component.
- If the read is legitimately one-off (e.g. logging), disable the flag locally or globally: configure({ observableRequiresReaction: false }).
- Remove requiresObservable: true from observables that are read imperatively by design.
- Use toJS() in non-reactive utility code if you just need a snapshot.
Example fix
// before (observableRequiresReaction: true)
function logCount(store) {
console.log(store.count) // read outside reactive context
}
// after
import { autorun } from 'mobx'
autorun(() => console.log(store.count)) Defensive patterns
Strategy: validation
Validate before calling
import { _getGlobalState, configure } from 'mobx'
// ensure reads happen in reactive contexts when this flag is on:
// configure({ observableRequiresReaction: false }) // for imperative utility code
function canReadReactively() {
return _getGlobalState().trackingDerivation !== null || !_getGlobalState().observableRequiresReaction
} Prevention
- Only enable observableRequiresReaction on codebases that are fully reactive-context based.
- Use toJS() for one-off snapshots in plain functions.
- Wrap console/debug reads in autorun during development.
When it happens
Trigger: Reading an observable's .get() or property value in plain imperative code (not inside computed/reaction/observer render) while configure({ observableRequiresReaction: true }) is set, or the observable was created with requiresObservable: true (e.g. via options on observable/annotation).
Common situations: Debugging in the console with observableRequiresReaction left on; reading store values inside plain utility functions called outside renderers; unit tests reading observables directly; onBecomeObserved-style code paths invoked outside tracking.
Related errors
- [mobx] Derivation '${derivation.name_}' is created/updated w
- mobx-react-lite requires mobx at least version 7 to be avail
- mobx-react requires mobx to be available
- [mobx-react] Cannot read "${admin.name}.${key}" in a reactiv
- [MobX] ${e}
AI-assisted analysis of mobxjs/mobx@01211a698b (2026-08-28).
Data as JSON: /api/errors/c9f3c469a993efa8.
Report an issue: GitHub.