facebook/react · error · Error

191

191

Error message

Invalid argument passed as callback. Expected a function. Instead received: ${callback}

What it means

callCallback() invokes the second argument of a class component's setState()/forceUpdate() after the update commits. React stores that argument in the update queue and runs it through callCallback, which hard-asserts it is a function. The message echoes the invalid value, so 'received: [object Object]' means an object was passed where the callback belongs.

Source

Thrown at packages/react-reconciler/src/ReactFiberClassUpdateQueue.js:702

    // This should be fine because the only two other things that contribute to
    // expiration time are props and context. We're already in the middle of the
    // begin phase by the time we start processing the queue, so we've already
    // dealt with the props. Context in components that specify
    // shouldComponentUpdate is tricky; but we'll have to account for
    // that regardless.
    markSkippedUpdateLanes(newLanes);
    workInProgress.lanes = newLanes;
    workInProgress.memoizedState = newState;
  }

  if (__DEV__) {
    currentlyProcessingQueue = null;
  }
}

function callCallback(callback: () => mixed, context: any) {
  if (typeof callback !== 'function') {
    throw new Error(
      'Invalid argument passed as callback. Expected a function. Instead ' +
        `received: ${callback}`,
    );
  }

  callback.call(context);
}

export function resetHasForceUpdateBeforeProcessing() {
  hasForceUpdate = false;
}

export function checkHasForceUpdateAfterProcessing(): boolean {
  return hasForceUpdate;
}

export function deferHiddenCallbacks<State>(
  updateQueue: UpdateQueue<State>,

View on GitHub (pinned to eafeac097b)

Solutions

  1. Make the second argument a function or omit it: this.setState(next, () => { /* ... */ })
  2. Move options-object logic out of the second argument into the callback or componentDidUpdate
  3. Log typeof of the variable passed as callback to find the bad call site
  4. Library authors: validate callbacks from external callers before enqueueing updates

Example fix

// before
this.setState({count: next}, {onDone: this.finish});

// after
this.setState({count: next}, this.finish);
Defensive patterns

Strategy: type-guard

Validate before calling

safeSetState(partial, cb) {
  if (cb !== undefined && typeof cb !== 'function') {
    throw new TypeError(`setState callback must be a function, got ${typeof cb}`);
  }
  this.setState(partial, cb);
}

Type guard

const isCallback = (cb) => cb == null || typeof cb === 'function';

Try / catch

The throw surfaces while processing the update; an ErrorBoundary near the component catches it. Fix the call site - the same invalid callback re-throws on every retry.

Prevention

When it happens

Trigger: this.setState({x: 1}, someNonFunction) - typically an options object, a string, or a function invoked instead of passed (this.setState(s, cb())); this.forceUpdate('x'); third-party code calling enqueueSetState(instance, state, callback) with a malformed callback.

Common situations: Porting callback-style APIs from other frameworks; passing a useEffect-style options object as the second setState argument; refactors from promise-style setState(...).then(...) patterns; typos where a callback name is passed as a string.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/ae14a8563a29a302. Report an issue: GitHub.