mobxjs/mobx · warning

[mobx] Observable ' ' being read outside a reactive context.

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.

Solutions

  1. Read the value inside a reactive context: computed, reaction(), autorun(), or an observer component.
  2. If the read is legitimately one-off (e.g. logging), disable the flag locally or globally: configure({ observableRequiresReaction: false }).
  3. Remove requiresObservable: true from observables that are read imperatively by design.
  4. 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

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


AI-assisted analysis of mobxjs/mobx@01211a698b (2026-08-28). Data as JSON: /api/errors/c9f3c469a993efa8. Report an issue: GitHub.

Appendix: 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_.length

View on GitHub (pinned to 01211a698b)