streamich/react-use · error · Error

states expected to be an object or array, got ${typeof state

Error message

states expected to be an object or array, got ${typeof states}

What it means

Thrown by useMultiStateValidator when its first argument `states` is not of type 'object'. The hook expects a collection (an array or a record/object) of states to validate together, and rejects primitives up front. Caveat: the check is `typeof states !== 'object'`, and because typeof null === 'object', passing null bypasses this guard and will surface later as a different failure — the intended inputs are arrays and plain objects only.

Source

Thrown at src/useMultiStateValidator.ts:17

import { useCallback, useEffect, useRef, useState } from 'react';
import { StateValidator, UseStateValidatorReturn, ValidityState } from './useStateValidator';

export type MultiStateValidatorStates = any[] | { [p: string]: any } | { [p: number]: any };
export type MultiStateValidator<V extends ValidityState, S extends MultiStateValidatorStates> =
  StateValidator<V, S>;

export function useMultiStateValidator<
  V extends ValidityState,
  S extends MultiStateValidatorStates
>(
  states: S,
  validator: MultiStateValidator<V, S>,
  initialValidity: V = [undefined] as V
): UseStateValidatorReturn<V> {
  if (typeof states !== 'object') {
    throw new Error('states expected to be an object or array, got ' + typeof states);
  }

  const validatorInner = useRef(validator);
  const statesInner = useRef(states);

  validatorInner.current = validator;
  statesInner.current = states;

  const [validity, setValidity] = useState(initialValidity as V);

  const validate = useCallback(() => {
    if (validatorInner.current.length >= 2) {
      validatorInner.current(statesInner.current, setValidity);
    } else {
      setValidity(validatorInner.current(statesInner.current));
    }
  }, [setValidity]);

View on GitHub (pinned to fbe99c6327)

Solutions

  1. Pass states as an array or object: useMultiStateValidator([fieldA, fieldB], validator) or useMultiStateValidator({a, b}, validator).
  2. If the value can be undefined, default it to an empty structure: useMultiStateValidator(states ?? [], validator).
  3. Wrap a single state before passing: useMultiStateValidator([singleState], validator).
  4. Do not pass null — although it slips past this check, it is not a valid states collection; use {} or [] instead.

Example fix

// before
useMultiStateValidator(email, validateEmail);          // email is a primitive string
useMultiStateValidator(maybeStates, validator);         // maybeStates may be undefined

// after
useMultiStateValidator([email], validateEmail);
useMultiStateValidator(maybeStates ?? [], validator);
Defensive patterns

Strategy: type-guard

Validate before calling

function useMultiStateValidatorSafe<V extends ValidityState, S extends MultiStateValidatorStates>(
  states: S,
  validator: MultiStateValidator<V, S>,
  initialValidity?: V
) {
  if (states === null || typeof states !== 'object') {
    throw new Error('states must be a non-null object or array');
  }
  return useMultiStateValidator(states, validator, initialValidity);
}

// or coerce at the call site:
const safeStates = states ?? {};
useMultiStateValidator(safeStates, validator);

Type guard

// Accept arrays and plain objects; explicitly reject null (typeof null === 'object').
const isMultiState = (v: unknown): v is MultiStateValidatorStates =>
  (Array.isArray(v) || (typeof v === 'object' && v !== null));

if (isMultiState(states)) {
  useMultiStateValidator(states, validator);
}
// else: handle the primitive case before calling

Try / catch

// The hook throws during render; wrap the consumer in a boundary rather than
// try/catching the hook call, and fix the input via the type guard above.

Prevention

When it happens

Trigger: Calling useMultiStateValidator(states, validator, initialValidity) where states is a primitive (string, number, boolean, undefined, symbol, bigint). For example, passing a single state value instead of wrapping it in an array/object, or passing an optional prop that is undefined.

Common situations: Migrating from useStateValidator (single state) and forgetting to wrap the state in an array; passing an optional/derived prop that can be undefined; copy-paste where a primitive counter/flag is handed in directly.

Related errors


AI-assisted analysis of streamich/react-use@fbe99c6327 (2026-08-12). Data as JSON: /api/errors/485cd1c83ac6de73. Report an issue: GitHub.