reduxjs/redux · error · Error
Actions must be plain objects. Instead, the actual type was:
Error message
Actions must be plain objects. Instead, the actual type was: '${kindOf(action)}'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions. See https://redux.js.org/tutorials/fundamentals/part-4-store#middleware and https://redux.js.org/tutorials/fundamentals/part-6-async-logic#using-the-redux-thunk-middleware for examples. What it means
dispatch() requires its argument to be a plain object — an action literal like { type, payload } produced by {} or Object.create(null). Functions, Promises, class instances, arrays, and primitive values are rejected because the core dispatch pipeline is synchronous and assumes a serializable action. To dispatch non-plain values you must add middleware (e.g. redux-thunk for functions).
Source
Thrown at src/createStore.ts:272
* dispatch a Promise, an Observable, a thunk, or something else, you need to
* wrap your store creating function into the corresponding middleware. For
* example, see the documentation for the `redux-thunk` package. Even the
* middleware will eventually dispatch plain object actions using this method.
*
* @param action A plain object representing “what changed”. It is
* a good idea to keep actions serializable so you can record and replay user
* sessions, or use the time travelling `redux-devtools`. An action must have
* a `type` property which may not be `undefined`. It is a good idea to use
* string constants for action types.
*
* @returns For convenience, the same action object you dispatched.
*
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
* return something else (for example, a Promise you can await).
*/
function dispatch(action: A) {
if (!isPlainObject(action)) {
throw new Error(
`Actions must be plain objects. Instead, the actual type was: '${kindOf(
action
)}'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions. See https://redux.js.org/tutorials/fundamentals/part-4-store#middleware and https://redux.js.org/tutorials/fundamentals/part-6-async-logic#using-the-redux-thunk-middleware for examples.`
)
}
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. You may have misspelled an action type string constant.'
)
}
if (typeof action.type !== 'string') {
throw new Error(
`Action "type" property must be a string. Instead, the actual type was: '${kindOf(
action.type
)}'. Value was: '${String(action.type)}' (stringified)`
)View on GitHub (pinned to 3084fc33bb)
Solutions
- Invoke action creators: `dispatch(addTodo(text))`, not `dispatch(addTodo)`.
- Apply redux-thunk (or redux-saga, redux-observable) via applyMiddleware to handle functions/Promises/etc.
- If batching, install a batching middleware (e.g. redux-batched-actions) rather than dispatching arrays.
- Confirm class-instance actions are converted to plain objects ({...instance}) before dispatch.
Example fix
// before
dispatch(addTodo) // passing the function, not its result
const store = createStore(rootReducer) // no thunk middleware
// after
import { applyMiddleware, createStore } from 'redux'
import thunk from 'redux-thunk'
const store = createStore(rootReducer, applyMiddleware(thunk))
dispatch(addTodo('buy milk')) // plain object
dispatch(fetchTodos()) // thunk, handled by middleware Defensive patterns
Strategy: type-guard
Validate before calling
const isPlainAction = a =>
a !== null && typeof a === 'object' &&
(Object.getPrototypeOf(a) === null || Object.getPrototypeOf(a) === Object.prototype)
if (!isPlainAction(action)) {
console.error('dispatch expects a plain object; got', action)
} else {
store.dispatch(action)
} Type guard
const isPlainObjectAction = (x): x is { type: string; [k:string]: any } =>
x !== null && typeof x === 'object' &&
(Object.getPrototypeOf(x) === null || Object.getPrototypeOf(x) === Object.prototype)
&& typeof x.type === 'string' Prevention
- Always invoke action creators: dispatch(addTodo(text)).
- Install redux-thunk/saga before dispatching functions/Promises.
- Convert class instances to plain objects before dispatch.
- Use TypeScript so dispatch(action) only accepts plain Action-typed objects.
When it happens
Trigger: dispatch(myActionCreator) where the creator was called but you forgot the parentheses; dispatch(() => ...) (a thunk) without redux-thunk applied; dispatch(Promise.resolve()); dispatch(new MyActionClass()); dispatch([action1, action2]) hoping for batch behavior.
Common situations: Forgot to call the action creator: `dispatch(addTodo)` instead of `dispatch(addTodo())`; thunks dispatched before applyMiddleware(thunk) is wired; passing a class instance action from a typed action factory; using Observable/Promise middleware that is not installed.
Related errors
- Dispatching while constructing your middleware is not allowe
- Actions may not have an undefined "type" property. You may h
- Action "type" property must be a string. Instead, the actual
- Reducers may not dispatch actions.
- Expected the root reducer to be a function. Instead, receive
AI-assisted analysis of reduxjs/redux@3084fc33bb (2026-08-12).
Data as JSON: /api/errors/b683dca4ff77b2e8.
Report an issue: GitHub.