Skip to content

Maximum call stack size exceeded in actuallyMutateSubscriptions when using persistReducer as a nested slice in a large RTK store with PersistGate #5283

@BentolhodaAhmadi

Description

@BentolhodaAhmadi

Environment:

Library Version
redux-persist "^6.0.0"
@reduxjs/toolkit "^2.3.0"
react-redux "^9.1.2"
react "19.2.0"

Description:

When using persistReducer as a nested slice (not root reducer) inside a large RTK configureStore that contains many RTK Query API reducers, and using PersistGate with persistStore(store), the app throws a stack overflow during render.
Minimal reproduction of the setup:

  1. tabs.util.ts — persisted slice definition:
import { combineReducers } from "@reduxjs/toolkit";
import { persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import tabsReducer from "./tabs.slice";

const rootReducer = combineReducers({ tabs: tabsReducer });
const persistConfig = { key: "tabs-core", storage };

export const persistedReducer = persistReducer(persistConfig, rootReducer);
  1. shared-common-apps-store.ts — nested inside main store:
export const sharedCommonAppsReducerStore = {
  persistedReducer: persistedReducer, // ← nested persisted reducer
  preservedAppIdSlice: preservedAppIdSlice.reducer,
  triggerPasteReducer: triggerPasteReducer,
  [personsApi.reducerPath]: personsApi.reducer,
  // ... ~40 more RTK Query API reducers
};
  1. store.ts — main store:
export const store = configureStore({
  reducer: {
    ...sharedCommonAppsReducerStore, // contains persistedReducer as nested slice
    ...accountingReducerStore,
    ...treasuryReducerStore,
    ...generalReducerStore,
    ...sharedServiceReducerStore,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware()
      .prepend(listenerMiddleware.middleware)
      .concat(mergeMiddlewareStore)
      .concat(rtkQueryErrorLogger),
});
  1. SharedProviders.tsxPersistGate usage:
export function SharedProviders({ theme, children, store }) {
  const persistor = persistStore(store); // called on the main store

  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        {children}
      </PersistGate>
    </Provider>
  );
}
  1. App.tsx — entry point:
export function App() {
  const theme = useMemo(() => createSharedTheme(), []);
  return (
    <SharedProviders theme={theme} store={store}>
      <RouterProvider router={router} />
    </SharedProviders>
  );
}
Error:
RangeError: Maximum call stack size exceeded
    at actuallyMutateSubscriptions (chunk-JVMNWONT.js:2000:39)
    at chunk-JVMNWONT.js:2089:23
    at chunk-JVMNWONT.js:2717:61
    at chunk-JVMNWONT.js:2720:17
    at chunk-JVMNWONT.js:2720:17
    ... (repeating)

What I tried:

  • Moving persistStore outside of React component → same error
  • Using useRef(() => persistStore(store)) → same error
  • Adding serializableCheck ignored actions → same error
  • Creating a separate store just for persistStore → different error (PersistGate and Provider on different stores)
  • Removing persistedReducer from the store → error disappears ✅
  • Removing PersistGate → error disappears ✅

Question:

Is using persistReducer as a nested slice (not root reducer) with PersistGate on the main store a supported pattern? The error only appears when the store has a large number of reducers (~50+). With fewer reducers it seems to work fine.
If this pattern is not supported, what is the recommended approach for persisting only a subset of the Redux state?

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionFurther information is requestedRTK-QueryIssues related to Redux-Toolkit-Query

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions