streamich/react-use · error · Error

State ' ' is not a valid state (does not exist in state…

Error message

State '${state}' is not a valid state (does not exist in state list)

What it means

Thrown by the `setState` function returned from useStateList when the requested state value is not present in the configured state list. Internally setState looks up the index via stateSet.indexOf(state); if it returns -1 (not found), the library refuses to move to a non-existent state and throws. There is an isMounted() guard first, so the throw only occurs while the component is mounted.

Solutions

  1. Pass only values that exist in the state list; reference the same constants/literals used to build the list.
  2. Validate membership before calling: if (states.includes(next)) setState(next); else handle the unknown state.
  3. For object states, compare by a stable key/id rather than passing a newly-constructed object, or store the canonical members and reuse references.
  4. Double-check casing/whitespace of string states against the list definition.

Example fix

// before
const [state, controls] = useStateList(['open', 'closed', 'pending']);
controls.setState('Open');   // throws: 'open' !== 'Open'

// after
controls.setState('open');
// or guard:
if (['open','closed','pending'].includes(next)) controls.setState(next);
Defensive patterns

Strategy: validation

Validate before calling

const states = ['open', 'closed', 'pending'] as const;
const [, controls] = useStateList(states);

function safeSetState(next: string) {
  if (states.includes(next as (typeof states)[number])) {
    controls.setState(next);
  } else {
    console.warn(`Unknown state: ${next}`);
  }
}

Type guard

const STATES = ['open', 'closed', 'pending'] as const;
type State = (typeof STATES)[number];

const isState = (v: unknown): v is State =>
  typeof v === 'string' && (STATES as readonly string[]).includes(v);

if (isState(next)) controls.setState(next);
// else: ignore or log — never call setState with an unknown value

Try / catch

try {
  controls.setState(next);
} catch (e) {
  // setState is user-triggered (not render), so try/catch is viable here:
  console.warn(`Rejected state transition to '${next}': not in list`, e);
}

Prevention

When it happens

Trigger: Calling controls.setState(someValue) where someValue is not an element of the state list passed to useStateList. Examples: a typo in an enum/union value, a value from a different casing, or an externally-derived value that does not exactly match a list member (also affected by reference equality for object states).

Common situations: String/enum mismatches ('Open' vs 'open'); copy-pasting a state machine whose labels differ; object states compared by reference where a fresh object is passed instead of the original list member; deserialized JSON values that do not match the literal list entries.

Related errors


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

Appendix: source

Thrown at src/useStateList.ts:60

        if (newIndex === index.current) return;

        // it gives the ability to travel through the left and right borders.
        // 4ex: if list contains 5 elements, attempt to set index 9 will bring use to 5th element
        // in case of negative index it will start counting from the right, so -17 will bring us to 4th element
        index.current =
          newIndex >= 0
            ? newIndex % stateSet.length
            : stateSet.length + (newIndex % stateSet.length);
        update();
      },
      setState: (state: T) => {
        // do nothing on unmounted component
        if (!isMounted()) return;

        const newIndex = stateSet.length ? stateSet.indexOf(state) : -1;

        if (newIndex === -1) {
          throw new Error(`State '${state}' is not a valid state (does not exist in state list)`);
        }

        index.current = newIndex;
        update();
      },
    }),
    [stateSet]
  );

  return {
    state: stateSet[index.current],
    currentIndex: index.current,
    isFirst: index.current === 0,
    isLast: index.current === stateSet.length - 1,
    ...actions,
  };
}

View on GitHub (pinned to fbe99c6327)