# What Validation Does Redux Perform on Action Objects in Dispatch?

> Redux validates dispatched actions, ensuring they are plain objects with a string type property. Learn about Redux action validation and avoid common errors.

- Repository: [Redux/redux](https://github.com/reduxjs/redux)
- Tags: how-to-guide
- Published: 2026-03-05

---

**Redux validates every dispatched action by verifying it is a plain JavaScript object with a defined string `type` property, throwing descriptive errors immediately if any check fails.**

When you call `store.dispatch(action)` in the reduxjs/redux repository, the library enforces strict requirements before the action reaches your reducers. These validation steps ensure action serializability, enable time-travel debugging, and maintain predictable state management across your application.

## The Three-Step Validation Process in Redux Dispatch

The `dispatch` function in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) performs three sequential validation checks on every action object between lines 81 and 101.

### Step 1: Plain Object Validation

First, Redux verifies the action is a plain JavaScript object using the `isPlainObject` utility from [`src/utils/isPlainObject.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/isPlainObject.ts). This check fails for class instances, arrays, functions, or `null` values.

In [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) (lines 81-84), if this check fails, Redux throws:

```typescript
if (!isPlainObject(action)) {
  throw new Error(
    `Actions must be plain objects. Instead, the actual type was: '${kindOf(
      action
    )}'. You may need to add middleware …`
  )
}

```

### Step 2: Type Property Existence Check

Second, Redux checks that the `type` property is not `undefined`. This validation occurs at lines 89-93 of [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts):

```typescript
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.'
  )
}

```

### Step 3: Type Property String Validation

Finally, Redux verifies that `action.type` is a string. This check at lines 95-101 prevents numeric or symbolic action types that could break serialization:

```typescript
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: '${action.type}' (stringified)`
  )
}

```

## Source Code Locations and Implementation Details

The validation logic spans several utility files in the reduxjs/redux repository:

| File | Purpose |
|------|---------|
| [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) | Contains the `dispatch` function with the three validation checks at lines 81-101. |
| [`src/utils/isPlainObject.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/isPlainObject.ts) | Exports `isPlainObject` to verify the action is a plain object, not a class instance or array. |
| [`src/utils/isAction.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/isAction.ts) | Combines all three checks into a reusable predicate for external validation. |
| [`src/utils/kindOf.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/kindOf.ts) | Generates human-readable type names used in error messages. |

## Practical Examples of Action Validation

### Valid Action Dispatch

```javascript
import { createStore } from 'redux'

function reducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT': return state + 1
    default: return state
  }
}

const store = createStore(reducer)
store.dispatch({ type: 'INCREMENT', payload: 1 })
// ✅ No error – plain object with string type

```

### Invalid: Class Instance Action

```javascript
class ActionClass {
  constructor() {
    this.type = 'ADD_TODO'
  }
}

store.dispatch(new ActionClass())
// ❌ Throws: "Actions must be plain objects. Instead, the actual type was: 'object'."

```

### Invalid: Missing Type Property

```javascript
store.dispatch({ payload: 42 })
// ❌ Throws: "Actions may not have an undefined "type" property."

```

### Invalid: Non-String Type

```javascript
store.dispatch({ type: 123 })
// ❌ Throws: "Action "type" property must be a string. Instead, the actual type was: 'number'."

```

## Handling Non-Plain Actions with Middleware

Redux's validation only applies to the core `dispatch` function. Middleware like `redux-thunk` intercepts actions before they reach the validation logic, allowing you to dispatch functions or other non-plain objects:

```javascript
import thunk from 'redux-thunk'
import { applyMiddleware, createStore } from 'redux'

const store = createStore(reducer, applyMiddleware(thunk))

// Dispatch a function (thunk) instead of a plain object
store.dispatch((dispatch, getState) => {
  setTimeout(() => {
    dispatch({ type: 'ASYNC_DONE' })
  }, 1000)
})
// ✅ No error – thunk middleware intercepts the function before validation

```

## Summary

Redux enforces three strict validation rules on every action dispatched to the store:

- **Plain Object Requirement**: Actions must be plain JavaScript objects, not class instances or arrays, verified by `isPlainObject` in [`src/utils/isPlainObject.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/isPlainObject.ts).
- **Type Property Existence**: The `type` property must be defined and cannot be `undefined`, checked at lines 89-93 of [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts).
- **String Type Requirement**: The `type` property must be a string value, validated at lines 95-101 of [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts).

These checks ensure action serializability and predictable reducer behavior, while middleware provides escape hatches for advanced patterns like thunks.

## Frequently Asked Questions

### What happens if I dispatch a class instance instead of a plain object?

Redux throws an error stating "Actions must be plain objects" because class instances fail the `isPlainObject` check in [`src/utils/isPlainObject.ts`](https://github.com/reduxjs/redux/blob/main/src/utils/isPlainObject.ts). To fix this, use object literals like `{ type: 'ACTION' }` or ensure your action creators return plain objects rather than class instances.

### Can I use symbols for action types in Redux?

No, Redux explicitly requires the `type` property to be a string. The validation at lines 95-101 of [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) checks `typeof action.type !== 'string'` and throws an error if you pass a symbol, number, or other non-string value. This requirement ensures action types are serializable and can be logged or replayed.

### Why does Redux require actions to be plain objects?

Plain objects are serializable, which enables Redux DevTools features like time-travel debugging, state persistence, and action replay. The `isPlainObject` utility ensures actions can be safely logged, stored, and rehydrated without losing information or carrying unexpected prototype chains.

### How can I dispatch functions or promises if Redux only accepts plain objects?

You can use middleware like `redux-thunk` or `redux-promise` to intercept non-plain actions before they reach the core `dispatch` validation. Middleware sits between your `store.dispatch()` call and the validation logic in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts), allowing you to dispatch thunks, promises, or other custom payloads while still eventually dispatching plain objects to the reducers.