{"record":{"id":"eba1e8d16c5b7207","repo":"petkaantonov/bluebird","slug":"oncancel-must-be-a-function-got-s","errorCode":null,"errorMessage":"onCancel must be a function, got: %s","messagePattern":"onCancel must be a function, got: (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/debuggability.js","lineNumber":414,"sourceCode":"Promise.prototype._setOnCancel = function (handler) { USE(handler); };\nPromise.prototype._attachCancellationCallback = function(onCancel) {\n    USE(onCancel);\n};\nPromise.prototype._captureStackTrace = function () {};\nPromise.prototype._attachExtraTrace = function () {};\nPromise.prototype._dereferenceTrace = function () {};\nPromise.prototype._clearCancellationData = function() {};\nPromise.prototype._propagateFrom = function (parent, flags) {\n    USE(parent);\n    USE(flags);\n};\n\nfunction cancellationExecute(executor, resolve, reject) {\n    var promise = this;\n    try {\n        executor(resolve, reject, function(onCancel) {\n            if (typeof onCancel !== \"function\") {\n                throw new TypeError(\"onCancel must be a function, got: \" +\n                                    util.toString(onCancel));\n            }\n            promise._attachCancellationCallback(onCancel);\n        });\n    } catch (e) {\n        return e;\n    }\n}\n\nfunction cancellationAttachCancellationCallback(onCancel) {\n    if (!this._isCancellable()) return this;\n\n    var previousOnCancel = this._onCancel();\n    if (previousOnCancel !== undefined) {\n        if (util.isArray(previousOnCancel)) {\n            previousOnCancel.push(onCancel);\n        } else {\n            this._setOnCancel([previousOnCancel, onCancel]);","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/petkaantonov/bluebird/blob/c220cfe480868e2f5c5de4fe8bb3b04b97588d7f/src/debuggability.js#L396-L432","documentation":"When an executor uses Bluebird's third executor argument (the onCancel registration callback), the value passed must be a function. cancellationExecute validates typeof onCancel and throws a TypeError('onCancel must be a function, got: %s') otherwise. The onCancel callback is what Bluebird invokes to roll back work when the promise is cancelled, so a non-function is always a caller bug.","triggerScenarios":"new Promise((resolve, reject, onCancel) => { onCancel(someNonFunction) }) — e.g. onCancel(someVar) where someVar is undefined, null, a number, or the result of a misreferenced identifier; also passing a truthy non-function like a promise or config object.","commonSituations":"Passing the wrong variable to onCancel; expecting onCancel to accept a value/reason instead of a function; typos like onCancel(this.cleanup) where cleanup is undefined; copy-paste errors when adding cancellation support to executors.","solutions":["Pass an actual function: onCancel(() => cleanup())","Check the variable passed to onCancel is defined and a function (typeof x === 'function')","Remember onCancel takes a callback, not a reason string — move reason into your own closure state","Wrap executor body so a bad onCancel call rejects rather than crashes the constructor"],"exampleFix":"// before\nnew Promise((resolve, reject, onCancel) => {\n  onCancel('request aborted'); // not a function\n});\n// after\nnew Promise((resolve, reject, onCancel) => {\n  onCancel(() => socket.close('request aborted'));\n});","handlingStrategy":"type-guard","validationCode":"new Promise((resolve, reject, onCancel) => {\n  const cb = () => cleanup();\n  if (typeof cb !== 'function') throw new TypeError('onCancel callback must be a function');\n  onCancel(cb);\n  ...\n});","typeGuard":"function isOnCancelCallback(fn) {\n  return typeof fn === 'function';\n}","tryCatchPattern":"new Promise((resolve, reject, onCancel) => {\n  try {\n    onCancel(() => rollback());\n    doWork(resolve, reject);\n  } catch (e) {\n    reject(e);\n  }\n});","preventionTips":["Always pass a closure to onCancel, never a value or reason string","Keep the rollback logic in a named function so its type is obvious","Lint executor callbacks for onCancel argument usage","Add a unit test that cancels a promise to exercise the onCancel path"],"tags":["typeerror","cancellation","executor"],"backgroundTag":"oncancel-must-be-a-function","analyzedSha":"c220cfe480868e2f5c5de4fe8bb3b04b97588d7f","analyzedAt":"2026-09-02T02:30:20.863Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}