This error occurs in Redux Toolkit when using Immer incorrectly in reducers. It happens when you try to both mutate the draft state AND return a new value, which violates Immer's rules. The fix involves understanding how Immer works with Redux Toolkit's createReducer or createSlice.
The "return value must be a new object, not the draft" error is thrown by Immer when used with Redux Toolkit. Immer allows you to write reducers that appear to mutate state directly, but internally it tracks changes to produce an immutable update. This error occurs when you violate Immer's core rule: you must either mutate the draft state OR return a new state value, but not both. Redux Toolkit uses Immer internally with createReducer and createSlice, so this error typically appears when writing reducer logic incorrectly.
Change arrow functions that implicitly return to either mutate OR return explicitly:
// Incorrect - both mutates AND returns
const reducer = createReducer(initialState, (builder) => {
builder.addCase(someAction, (state, action) => {
state.value = action.payload; // Mutation
return state; // Explicit return - ERROR!
});
});
// Correct - only mutate
const reducer = createReducer(initialState, (builder) => {
builder.addCase(someAction, (state, action) => {
state.value = action.payload; // Just mutate, no return
});
});
// Also correct - only return (no mutation)
const reducer = createReducer(initialState, (builder) => {
builder.addCase(someAction, (state, action) => {
return { ...state, value: action.payload }; // Return new object
});
});Choose one pattern and stick with it throughout your reducer:
// Choose EITHER mutation style:
case 'UPDATE_VALUE':
draft.value = action.payload;
// No return statement - Immer handles it
break;
// OR return style:
case 'UPDATE_VALUE':
return {
...state,
value: action.payload
};
// NOT both:
case 'UPDATE_VALUE':
draft.value = action.payload; // Mutation
return draft; // Return - ERROR!Ensure Redux Toolkit and Immer versions are compatible:
# Check installed versions
npm list immer redux @reduxjs/toolkit
# If there's a version mismatch, let Redux Toolkit manage Immer:
npm uninstall immer
npm install @reduxjs/toolkit
# Redux Toolkit will bring its own compatible Immer versionRedux Toolkit ships with a specific Immer version. Manually installing a different Immer version can cause this error.
When you need to inspect draft state during debugging, use Immer's current() utility:
import { current } from '@reduxjs/toolkit';
const reducer = createReducer(initialState, (builder) => {
builder.addCase(someAction, (state, action) => {
console.log('Current draft state:', current(state));
state.value = action.payload;
// No return needed
});
});
// current() creates a plain copy for inspection without affecting the draftIf you need to convert existing code, here's how to switch patterns:
// From mutation to return style:
// Before:
state.items.push(action.payload);
// After:
return {
...state,
items: [...state.items, action.payload]
};
// From return to mutation style:
// Before:
return { ...state, count: state.count + 1 };
// After:
state.count += 1;Remember: With mutation style, you modify properties directly on the draft. With return style, you create and return a new object.
Redux Toolkit's createReducer and createSlice use Immer internally to enable "mutative" syntax while maintaining immutability. Immer works by creating a draft proxy that records mutations. When the reducer finishes, Immer produces the next immutable state based on those mutations. The error occurs when Immer detects both mutations AND a return value, which creates ambiguity about which state should be used. This is a protective measure to prevent subtle bugs. In complex reducers, you might need to use Immer's produce function directly for nested updates, but be careful not to mix patterns.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite