Skip to content

Non-Serializable Value Error in Redux Toolkit State

Why This Error Occurs

Redux Toolkit includes middleware that automatically checks for non-serializable values in your state and actions. This error occurs when your Redux state contains values that cannot be serialized - typically class instances, functions, Promises, or other complex objects.

The error message points to the specific path in your state where the non-serializable value was detected:

A non-serializable value was detected in the state, in the path: `varietals.red.0`.

Root Cause: Class Instances in State

The most common cause is storing class instances in your Redux state. In your case:

javascript
class Varietal {
  constructor(id, color, varietal, isSelected, isCommon) {
    this.id = id;
    this.color = color;
    this.varietal = varietal;
    this.isSelected = isSelected;
    this.isCommon = isCommon;
  }
}

// This creates non-serializable class instances
const createVarietalArray = (arr, color, isCommon) =>
  arr.map(v => new Varietal(uuidv5(v, NAMESPACE), color, v, false, isCommon));

Class instances contain prototype chains and potential methods that cannot be properly serialized with JSON.stringify(), which Redux uses internally.

Replace class instances with plain JavaScript objects:

javascript
// Use plain objects instead of class instances
export const createVarietalArray = (arr, color, isCommon) =>
  arr.map(v => ({
    id: uuidv5(v, NAMESPACE),
    color,
    varietal: v,
    isSelected: false,
    isCommon,
  }));

This approach maintains the same data structure but uses serializable plain objects instead of class instances.

Alternative Approaches

You can disable the serialization check middleware, but this is generally not advised:

javascript
import { configureStore } from '@reduxjs/toolkit';

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false,
    }),
});

WARNING

Disabling serialization checks removes an important safeguard and may lead to hard-to-debug issues in your application.

2. Selective Ignoring of Actions or Paths

A better alternative is to selectively ignore specific actions or paths:

javascript
const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: ['your/action/type'],
        ignoredActionPaths: ['meta.arg', 'payload.timestamp'],
        ignoredPaths: ['items.dates'],
      },
    }),
});

3. Using with Redux Persist

If you're using Redux Persist, include these specific ignored actions:

javascript
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist';
import storage from 'redux-persist/lib/storage';

const persistConfig = {
  key: 'root',
  storage,
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
});

export const persistor = persistStore(store);

Best Practices

  1. Use Plain JavaScript Objects: Redux state should contain only serializable data
  2. Keep State Minimal: Store only the data needed for your UI
  3. Use Selectors for Derived Data: Compute derived data in selectors rather than storing it
  4. Normalize Data: Use normalized state shape for better performance

TIP

While you can disable serialization checks, the recommended approach is to fix the underlying issue by ensuring your state contains only serializable values.

When to Use Non-Serializable Values

There are limited cases where non-serializable values might be acceptable:

  • When using with Redux Persist (with the specific ignored actions shown above)
  • When dealing with unique identifiers like UUIDs that have specific formatting requirements
  • When using middleware that handles serialization internally

Even in these cases, it's better to handle serialization at the boundary of your Redux store rather than storing non-serializable values directly in the state.

Summary

The "non-serializable value" error in Redux Toolkit is a helpful warning that prevents common Redux anti-patterns. The optimal solution is to refactor your code to use plain JavaScript objects instead of class instances in your Redux state. While workarounds exist to disable the checks, they remove important safeguards and should be used sparingly and with caution.