reduxjs/redux · error · Error
You may not call store.subscribe() while the reducer is exec
Error message
You may not call store.subscribe() while the reducer is executing. If you would like to be notified after the store has been updated, subscribe from a component and invoke store.getState() in the callback to access the latest state. See https://redux.js.org/api/store#subscribelistener for more details.
What it means
Subscribing during a dispatch would mutate the listener set mid-iteration and could let the new listener fire for an action it never asked about, or skip listeners entirely. Redux uses the isDispatching guard on subscribe() so new subscriptions only take effect from the next dispatch onward, and the snapshotted listener set stays stable for the current one.
Source
Thrown at src/createStore.ts:211
* might have been updated multiple times during a nested `dispatch()` before
* the listener is called. It is, however, guaranteed that all subscribers
* registered before the `dispatch()` started will be called with the latest
* state by the time it exits.
*
* @param listener A callback to be invoked on every dispatch.
* @returns A function to remove this change listener.
*/
function subscribe(listener: () => void) {
if (typeof listener !== 'function') {
throw new Error(
`Expected the listener to be a function. Instead, received: '${kindOf(
listener
)}'`
)
}
if (isDispatching) {
throw new Error(
'You may not call store.subscribe() while the reducer is executing. ' +
'If you would like to be notified after the store has been updated, subscribe from a ' +
'component and invoke store.getState() in the callback to access the latest state. ' +
'See https://redux.js.org/api/store#subscribelistener for more details.'
)
}
let isSubscribed = true
ensureCanMutateNextListeners()
const listenerId = listenerIdCounter++
nextListeners.set(listenerId, listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
View on GitHub (pinned to 3084fc33bb)
Solutions
- Move the subscribe call out of the reducer/dispatch path; subscribe at module load or component-mount time, before any dispatch.
- If a listener needs to register another listener, defer with queueMicrotask/setTimeout so the new subscription lands after the current dispatch.
- Restructure so conditional subscriptions are decided up front rather than mid-dispatch.
Example fix
// before
store.subscribe(() => {
if (firstRun) store.subscribe(extraListener) // throws: dispatch in progress
})
// after
store.subscribe(() => {
if (firstRun) queueMicrotask(() => store.subscribe(extraListener))
}) Defensive patterns
Strategy: validation
Validate before calling
// Schedule any subscribe call that might run during dispatch:
const safeSubscribe = (store, listener) => {
if (typeof queueMicrotask === 'function') {
queueMicrotask(() => store.subscribe(listener))
} else {
setTimeout(() => store.subscribe(listener), 0)
}
} Prevention
- Subscribe at module/component-mount time, never inside a reducer or dispatch path.
- Defer mid-dispatch subscriptions with a microtask.
- Keep subscribe/unsubscribe out of the listener callback body.
When it happens
Trigger: A reducer that calls store.subscribe(); a subscriber callback that subscribes a second listener while iterating; middleware that calls api.subscribe() during next(action); code that subscribes inside an existing listener without deferring.
Common situations: Hot-reload or code-splitting logic that wires up new subscriptions during an action; component-lifecycle code invoked synchronously during dispatch; subscriber that conditionally registers more listeners based on the action.
Related errors
- You may not unsubscribe from a store listener while the redu
- You may not call store.getState() while the reducer is execu
- Expected the listener to be a function. Instead, received: '
- Reducers may not dispatch actions.
- Expected the root reducer to be a function. Instead, receive
AI-assisted analysis of reduxjs/redux@3084fc33bb (2026-08-12).
Data as JSON: /api/errors/7c46cd1fadf8ecec.
Report an issue: GitHub.