reduxjs/redux · error · Error

Expected the enhancer to be a function. Instead, received: '

Error message

Expected the enhancer to be a function. Instead, received: '${kindOf(enhancer)}'

What it means

When createStore receives a third argument (or second, after the preloadedState-shift), it treats it as a store enhancer and must be callable. If the value is non-function (e.g. an object, string, or a devtools config), Redux cannot apply it because enhancers are functions of (createStore) => (reducer, preloadedState) => store.

Source

Thrown at src/createStore.ts:123

  if (
    (typeof preloadedState === 'function' && typeof enhancer === 'function') ||
    (typeof enhancer === 'function' && typeof arguments[3] === 'function')
  ) {
    throw new Error(
      'It looks like you are passing several store enhancers to ' +
        'createStore(). This is not supported. Instead, compose them ' +
        'together to a single function. See https://redux.js.org/tutorials/fundamentals/part-4-store#creating-a-store-with-enhancers for an example.'
    )
  }

  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState as StoreEnhancer<Ext, StateExt>
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error(
        `Expected the enhancer to be a function. Instead, received: '${kindOf(
          enhancer
        )}'`
      )
    }

    return enhancer(createStore)(
      reducer,
      preloadedState as PreloadedState | undefined
    )
  }

  let currentReducer = reducer
  let currentState: S | PreloadedState | undefined = preloadedState as
    | PreloadedState
    | undefined
  let currentListeners: Map<number, ListenerCallback> | null = new Map()
  let nextListeners = currentListeners

View on GitHub (pinned to 3084fc33bb)

Solutions

  1. Ensure the enhancer argument is the function returned by applyMiddleware(...) or compose(...), not the result of calling a devtools factory incorrectly.
  2. Use `window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose` to build a single function enhancer.
  3. Log `typeof enhancer` before createStore to confirm it is 'function'.
  4. Remove any stray third argument that was meant to be preloadedState (it was shifted incorrectly).

Example fix

// before
const store = createStore(
  rootReducer,
  applyMiddleware(thunk),            // preloadedState slot, gets shifted to enhancer OK
  window.__REDUX_DEVTOOLS_EXTENSION__ // an object, not a function -> throws
)

// after
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
  rootReducer,
  composeEnhancers(applyMiddleware(thunk))
)
Defensive patterns

Strategy: type-guard

Validate before calling

if (enhancer !== undefined && typeof enhancer !== 'function') {
  throw new TypeError(`enhancer must be a function, got ${typeof enhancer}`)
}
const store = createStore(reducer, preloadedState, enhancer)

Type guard

const isStoreEnhancer = (x): x is Function => typeof x === 'function'

Prevention

When it happens

Trigger: Passing window.__REDUX_DEVTOOLS_EXTENSION__() result incorrectly (calling compose on the extension object instead of the function); passing a configuration object where an enhancer function is expected; createStore(reducer, undefined, { trace: true }); typing-induced passing of a wrapped enhancer.

Common situations: Confusing redux-devtools-extension composeEnhancers with the raw devtools object; passing a preloaded-state object that is not detected as a function enhancer but then a third arg that is an object; migration where an enhancer was wrapped in an extra layer that returns an object.

Related errors


AI-assisted analysis of reduxjs/redux@3084fc33bb (2026-08-12). Data as JSON: /api/errors/16e1c7ba74ee8bfc. Report an issue: GitHub.