reduxjs/redux · error · Error
Action "type" property must be a string. Instead, the actual
Error message
Action "type" property must be a string. Instead, the actual type was: '${kindOf(action.type)}'. Value was: '${String(action.type)}' (stringified) What it means
After confirming type is defined, Redux also requires type to be a string. Symbols, numbers, objects, or booleans as type break devtools serialization, action recording, and string-based switch matching in reducers. The error includes kindOf and the stringified value to surface exactly what was passed.
Source
Thrown at src/createStore.ts:286
* 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)`
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = (currentListeners = nextListeners)View on GitHub (pinned to 3084fc33bb)
Solutions
- Use string constants for action types: `export const ADD_TODO = 'todos/add'`.
- If you want namespacing, prefix the string ('feature/ACTION') instead of using Symbols.
- Audit constant modules to confirm every exported type is `as const` string literal.
- If using a Symbol-based library, wrap it with middleware that maps Symbols to strings before they reach dispatch.
Example fix
// before
const ADD_TODO = Symbol('add')
dispatch({ type: ADD_TODO, payload: x }) // type is symbol -> throws
// after
const ADD_TODO = 'todos/add' as const
dispatch({ type: ADD_TODO, payload: x }) Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof action.type !== 'string') {
throw new TypeError(`Action type must be a string, got ${typeof action.type}`)
}
store.dispatch(action) Type guard
const hasStringType = (a): a is { type: string } =>
a !== null && typeof a === 'object' && typeof (a as any).type === 'string' Prevention
- Use string constants (or `as const` literals) for action types, never Symbols/numbers.
- Namespace via string prefixes ('feature/ACTION').
- Audit constant modules to ensure every type is a string literal.
- Type-check action creators so type is always a string.
When it happens
Trigger: dispatch({ type: Symbol('X') }) — using a Symbol type; dispatch({ type: 1 }) numeric type; dispatch({ type: { ns: 'X' } }) object type; a constants module that exports Symbols instead of strings (common in some Flux libraries).
Common situations: Mixing a Flux-constants library that exports Symbols; using enum numeric values from TypeScript as action types; intentional opaque types for namespacing that should instead use string prefixes; migrated code where types changed from string to Symbol.
Related errors
- Actions may not have an undefined "type" property. You may h
- Actions must be plain objects. Instead, the actual type was:
- Reducers may not dispatch actions.
- Dispatching while constructing your middleware is not allowe
- 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/3d203f05a3a4e88f.
Report an issue: GitHub.