{"record":{"id":"ae14a8563a29a302","repo":"facebook/react","slug":"191","errorCode":"191","errorMessage":"Invalid argument passed as callback. Expected a function. Instead received: ${callback}","messagePattern":"Invalid argument passed as callback\\. Expected a function\\. Instead received: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-reconciler/src/ReactFiberClassUpdateQueue.js","lineNumber":702,"sourceCode":"    // This should be fine because the only two other things that contribute to\n    // expiration time are props and context. We're already in the middle of the\n    // begin phase by the time we start processing the queue, so we've already\n    // dealt with the props. Context in components that specify\n    // shouldComponentUpdate is tricky; but we'll have to account for\n    // that regardless.\n    markSkippedUpdateLanes(newLanes);\n    workInProgress.lanes = newLanes;\n    workInProgress.memoizedState = newState;\n  }\n\n  if (__DEV__) {\n    currentlyProcessingQueue = null;\n  }\n}\n\nfunction callCallback(callback: () => mixed, context: any) {\n  if (typeof callback !== 'function') {\n    throw new Error(\n      'Invalid argument passed as callback. Expected a function. Instead ' +\n        `received: ${callback}`,\n    );\n  }\n\n  callback.call(context);\n}\n\nexport function resetHasForceUpdateBeforeProcessing() {\n  hasForceUpdate = false;\n}\n\nexport function checkHasForceUpdateAfterProcessing(): boolean {\n  return hasForceUpdate;\n}\n\nexport function deferHiddenCallbacks<State>(\n  updateQueue: UpdateQueue<State>,","sourceCodeStart":684,"sourceCodeEnd":720,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-reconciler/src/ReactFiberClassUpdateQueue.js#L684-L720","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the second argument a function or omit it: this.setState(next, () => { /* ... */ })","Move options-object logic out of the second argument into the callback or componentDidUpdate","Log typeof of the variable passed as callback to find the bad call site","Library authors: validate callbacks from external callers before enqueueing updates"],"exampleFix":"// before\nthis.setState({count: next}, {onDone: this.finish});\n\n// after\nthis.setState({count: next}, this.finish);","handlingStrategy":"type-guard","validationCode":"safeSetState(partial, cb) {\n  if (cb !== undefined && typeof cb !== 'function') {\n    throw new TypeError(`setState callback must be a function, got ${typeof cb}`);\n  }\n  this.setState(partial, cb);\n}","typeGuard":"const isCallback = (cb) => cb == null || typeof cb === 'function';","tryCatchPattern":"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.","preventionTips":["Type setState as setState<S>(state: S | ((prev: S) => S), callback?: () => void)","Never pass an options object as the second setState argument","Prefer componentDidUpdate over setState callbacks in new code"],"tags":["setstate","class-components","callback","validation"],"backgroundTag":"callback-not-a-function","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}