mobxjs/mobx · error

[mobx-react] Cannot read "${admin.name}.${key}" in a reactiv

Error message

[mobx-react] Cannot read "${admin.name}.${key}" in a reactive context, as it isn't observable.
                    Please use component lifecycle method to copy the value into a local observable first.
                    See https://github.com/mobxjs/mobx/blob/main/packages/mobx-react/README.md#note-on-using-props-and-state-in-derivations

What it means

When a component is wrapped with the class-based observer(), mobx-react replaces this.props and this.state with getters. Reading them inside a tracked derivation (e.g. inside a computed used during render, or another reaction) throws, because plain props/state are not observable values — tracking them produces no dependency and the derivation would silently never re-run. MobX throws early in __DEV__ to surface the invisible missing dependency.

Source

Thrown at packages/mobx-react/src/observerClass.ts:262

    if (this.state !== nextState) {
        return true
    }
    // update if props are shallowly not equal, inspired by PureRenderMixin
    // we could return just 'false' here, and avoid the `skipRender` checks etc
    // however, it is nicer if lifecycle events are triggered like usually,
    // so we return true here if props are shallowly modified.
    return !shallowEqual(this.props, nextProps)
}

function createObservablePropDescriptor(key: "props" | "state" | "context") {
    return {
        configurable: true,
        enumerable: true,
        get() {
            const admin = getAdministration(this)
            const derivation = _getGlobalState().trackingDerivation
            if (derivation && derivation !== admin.reaction) {
                throw new Error(
                    `[mobx-react] Cannot read "${admin.name}.${key}" in a reactive context, as it isn't observable.
                    Please use component lifecycle method to copy the value into a local observable first.
                    See https://github.com/mobxjs/mobx/blob/main/packages/mobx-react/README.md#note-on-using-props-and-state-in-derivations`
                )
            }
            return admin[key]
        },
        set(value) {
            getAdministration(this)[key] = value
        }
    }
}

View on GitHub (pinned to 01211a698b)

Solutions

  1. Copy the prop/state value into a local observable in the constructor or componentDidMount/UNSAFE_componentWillReceiveProps, and read the observable in the derivation instead
  2. Restructure so the computed takes the value as a parameter rather than reading this.props directly
  3. Pass props into child observable computeds at the call site inside render where the value is destructured untracked
  4. Use the function-component observer + useLocalObservable pattern, which avoids this.props getters entirely

Example fix

// before
class Store {
    get greeting() { return 'Hello ' + this.component.props.name }
}
// after
class MyComponent extends React.Component {
    name = observable.box(this.props.name)
    componentDidMount() { this.name.set(this.props.name) }
    get greeting() { return 'Hello ' + this.name.get() }
}
Defensive patterns

Strategy: validation

Validate before calling

// assert no tracked read of props/state inside derivations
function assertUntrackedRead(target: any, key: string) {
    const g = (require('mobx')._getGlobalState())
    if (g.trackingDerivation) {
        throw new Error(`Do not read ${key} inside a derivation; copy it to an observable first`)
    }
}

Type guard

function isInsideDerivation(): boolean {
    const { _getGlobalState } = require('mobx')
    return _getGlobalState().trackingDerivation != null
}

Try / catch

try {
    render()
} catch (e) {
    if (String(e).includes("isn't observable")) {
        console.error('Move this.props/this.state reads out of computeds into local observables', e)
    } else throw e
}

Prevention

When it happens

Trigger: Accessing `this.props.x` or `this.state.y` from inside a computed/value getter/derivation that runs during the observer component's render (any active trackingDerivation other than the component's own reaction), e.g. `get fullName() { return this.props.first + this.props.last }` evaluated in render.

Common situations: Defining MobX computeds on class components that read this.props/this.state; using computed values in autorun/reactions that touch component props; patterns that worked before mobx-react 6 where props were read freely.

Related errors


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