mobxjs/mobx · error
[mobx-react-lite] You are trying to use `observer` on a func
Error message
[mobx-react-lite] You are trying to use `observer` on a function component wrapped in either another `observer` or `React.memo`. The observer already applies 'React.memo' for you.
What it means
mobx-react-lite's `observer` already wraps the component in React.memo, so double-wrapping breaks the optimization and is rejected. This throw fires when the passed component's `$$typeof` equals `ReactMemoSymbol`, i.e. the input is a memoized component — which is exactly what `observer(...)` returns or what `React.memo(...)` produces. It is a developer-time contract check to prevent nested memo wrappers.
Source
Thrown at packages/mobx-react-lite/src/observer.ts:43
): React.FunctionComponent<P> & React.MemoExoticComponent<React.FunctionComponent<P>>
export function observer<P extends object, TRef = {}>(
baseComponent: React.ForwardRefExoticComponent<
React.PropsWithoutRef<P> & React.RefAttributes<TRef>
>
): React.MemoExoticComponent<
React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<TRef>>
>
// n.b. base case is not used for actual typings or exported in the typing files
export function observer<P extends object, TRef = {}>(
baseComponent:
| React.ForwardRefRenderFunction<TRef, P>
| React.FunctionComponent<P>
| React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<TRef>>
) {
if (ReactMemoSymbol && baseComponent["$$typeof"] === ReactMemoSymbol) {
throw new Error(
`[mobx-react-lite] You are trying to use \`observer\` on a function component wrapped in either another \`observer\` or \`React.memo\`. The observer already applies 'React.memo' for you.`
)
}
// The working of observer is explained step by step in this talk: https://www.youtube.com/watch?v=cPF4iBedoF0&feature=youtu.be&t=1307
if (isUsingStaticRendering()) {
return baseComponent
}
let useForwardRef = false
let render = baseComponent
const baseComponentName = baseComponent.displayName || baseComponent.name
// If already wrapped with forwardRef, unwrap,
// so we can patch render and apply memo
if (ReactForwardRefSymbol && baseComponent["$$typeof"] === ReactForwardRefSymbol) {
useForwardRef = trueView on GitHub (pinned to 01211a698b)
Solutions
- Pass the plain function component to `observer` and remove the outer `React.memo` — observer applies memoization itself.
- If wrapping multiple concerns with other HOCs, apply `observer` to the raw component and let other HOCs wrap the observer result.
- If you receive an already-observed component, use it directly instead of re-wrapping with `observer`.
Example fix
// before
const Cmp = React.memo(function MyComp(props) { return <div>{props.x}</div> })
export default observer(Cmp)
// after
function MyComp(props) { return <div>{props.x}</div> }
export default observer(MyComp) Defensive patterns
Strategy: validation
Validate before calling
function isMemoWrapped(Cmp) {
return Cmp && Cmp.$$typeof === Symbol.for('react.memo')
}
// before wrapping:
if (isMemoWrapped(Base)) Base = Base.type // unwrap memo before observer(Base)
observer(Base) Type guard
const isMemoComponent = (c) => !!c && typeof c === 'object' && c.$$typeof === Symbol.for('react.memo') Prevention
- Never wrap components in React.memo yourself when using mobx-react-lite — observer memoizes automatically.
- Keep HOC pipelines ordered: observer applied only once, closest to the raw component.
- Add a lint/CI check or helper wrapper that asserts the input is a plain function component.
When it happens
Trigger: Calling `observer(React.memo(Component))` or `observer(observer(Component))` — any function component whose `$$typeof` is `Symbol(react.memo)`.
Common situations: Incrementally migrating from manual React.memo to observer; composing HOCs in a pipeline where a component was already wrapped with observer; copy-pasting a memoized component into an observer call.
Related errors
- [mobx-react-lite] `render` property of ForwardRef was not a
- mobx-react-lite requires React 18 or later
- The provided component class (${displayName}) has already be
- [mobx-react] class component (${displayName}) is missing `re
- [mobx-react] `observer(${displayName}).componentDidMount` mu
AI-assisted analysis of mobxjs/mobx@01211a698b (2026-08-28).
Data as JSON: /api/errors/b05a9fb6e3ab5736.
Report an issue: GitHub.