How to fix Cannot mutate state in a non-immer reducer in React

ReactINTERMEDIATEMEDIUMUpdated Dec 10, 2025· 87 views

This error occurs when you try to directly mutate the state in a Redux reducer without using Immer. Redux requires immutable updates, and mutating state directly can cause components not to re-render and break time-travel debugging. This guide explains how to properly update state immutably in Redux reducers.

Quick fix

Fixes Cannot mutate state in a non-immer reducer

return {
  ...state,
  field: action.payload
};
  1. Identify the mutating operation
  2. Replace mutating operations with immutable updates
  3. Use Redux Toolkit for simpler immutable updates
  4. Verify your reducer is pure
react — error
return {
...state,
field: action.payload
};
Cannot mutate state in a non-immer reducer

What this error means

The error "Cannot mutate state in a non-immer reducer" indicates that you are attempting to modify the Redux state directly (e.g., by changing a property of an object or pushing to an array) in a reducer that is not wrapped by Immer. Redux relies on immutable state updates to detect changes efficiently. When you mutate state directly, Redux's shallow equality checks fail to detect the change, which can lead to UI not updating, broken time-travel debugging, and unpredictable behavior.

Typical symptoms

  • UI components connected to Redux store do not re-render when expected
  • Redux DevTools show state changes but the UI remains stale
  • Time-travel debugging does not work correctly
  • Console warnings about state mutations in development mode

Common causes

  1. Using mutating operations like `state.prop = value`, `state.array.push(item)`, or `state.nested.field = newValue` in a reducer
  2. Not using Immer or immutable update patterns when updating nested state
  3. Accidentally returning the same state object after mutating it
  4. Using Redux Toolkit's `createSlice` or `createReducer` without Immer in a custom configuration

How to fix "Cannot mutate state in a non-immer reducer"

1Identify the mutating operation

Look for places in your reducer where you are directly modifying the state object. Common patterns include assignment to properties (state.someField = action.payload), array methods that mutate in-place (push, pop, splice, sort), and modifying nested objects without copying.

2Replace mutating operations with immutable updates

For objects, use the spread operator to create a new object with the updated property:

javascript
return {
  ...state,
  field: action.payload
};

For arrays, use methods that return new arrays:

javascript
// Adding an item
return [...state, action.payload];
// Removing an item
return state.filter(item => item.id !== action.payload);
// Updating an item
return state.map(item => 
  item.id === action.payload.id ? { ...item, ...action.payload } : item
);
3Use Redux Toolkit for simpler immutable updates

Redux Toolkit includes Immer by default in createSlice and createReducer. You can write code that looks like it mutates state, but Immer safely produces immutable updates:

javascript
const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    todoAdded(state, action) {
      // This looks like a mutation but is safe with Immer
      state.push(action.payload);
    }
  }
});

Make sure you are using Redux Toolkit version 1.0 or later.

4Verify your reducer is pure

Ensure your reducer does not have side effects (like API calls, DOM manipulation) and always returns a new state object when changes occur. If no changes are needed, return the existing state object unchanged.

5Test the fix

After making changes, verify that your UI updates correctly and that Redux DevTools shows proper state changes. Use time-travel debugging to ensure each action produces a clean state snapshot.

Advanced notes

When using Immer with Redux Toolkit, remember that the "mutating" syntax only works inside reducers created with createSlice or createReducer. If you write a reducer manually without Immer, you must use traditional immutable update patterns. Also, Immer does not work with primitive state values (strings, numbers, booleans) – for those, you must return a new value directly. For large nested state updates, Immer can be more performant than manual immutable updates because it uses structural sharing.

Frequently asked questions

What does "Cannot mutate state in a non-immer reducer" mean?
, by changing a property of an object or pushing to an array) in a reducer that is not wrapped by Immer. Redux relies on immutable state updates to detect changes efficiently. When you mutate state directly, Redux's shallow equality checks fail to detect the change, which can lead to UI not updating, broken time-travel debugging, and unpredictable behavior.
How do I fix "Cannot mutate state in a non-immer reducer"?
This error occurs when you try to directly mutate the state in a Redux reducer without using Immer. Redux requires immutable updates, and mutating state directly can cause components not to re-render and break time-travel debugging. This guide explains how to properly update state immutably in Redux reducers.
What causes "Cannot mutate state in a non-immer reducer"?
Using mutating operations like state.prop = value, state.array.push(item), or state.nested.field = newValue in a reducer Not using Immer or immutable update patterns when updating nested state Accidentally returning the same state object after mutating it
Is the "Cannot mutate state in a non-immer reducer" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading