{"record":{"id":"890f5f0c730be44c","repo":"usablica/intro.js","slug":"provided-callback-for-onskip-was-not-a-function","errorCode":null,"errorMessage":"Provided callback for onskip was not a function.","messagePattern":"Provided callback for onskip was not a function\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/packages/tour/tour.ts","lineNumber":642,"sourceCode":"\n    this.callbacks.exit = callback;\n    return this;\n  }\n\n  /**\n   * @deprecated onskip is deprecated, please use onSkip instead.\n   */\n  onskip(callback: introSkipCallback) {\n    return this.onSkip(callback);\n  }\n\n  /**\n   * Add a callback to be called when the tour is skipped\n   * @param {Function} callback callback function to be called\n   */\n  onSkip(callback: introSkipCallback) {\n    if (!isFunction(callback)) {\n      throw new Error(\"Provided callback for onskip was not a function.\");\n    }\n\n    this.callbacks.skip = callback;\n    return this;\n  }\n\n  /**\n   * @deprecated onbeforeexit is deprecated, please use onBeforeExit instead.\n   */\n  onbeforeexit(callback: introBeforeExitCallback) {\n    return this.onBeforeExit(callback);\n  }\n\n  /**\n   * Add a callback to be called before the tour is exited\n   * @param {Function} callback callback function to be called\n   */\n  onBeforeExit(callback: introBeforeExitCallback) {","sourceCodeStart":624,"sourceCodeEnd":660,"githubUrl":"https://github.com/usablica/intro.js/blob/e5517e6a24e0530f87885af9fb2a69bafd1d4a6b/src/packages/tour/tour.ts#L624-L660","documentation":"Tour class onSkip registers the callback fired when the user skips the tour (via the skip button), stored in this.callbacks.skip. It throws when isFunction(callback) is false, matching the library-wide guard on callback registration methods.","triggerScenarios":"introJs().onSkip() or onSkip(nonFunction) — e.g., an analytics tracker string, a Promise, or an undefined config value.","commonSituations":"Passing an analytics library object hoping it will be invoked; optional telemetry callbacks that are conditionally configured; copy-paste from onExit wiring with a stale variable.","solutions":["Pass a function: introJs().onSkip(function(){ ... }).","Fix the argument source: correct the config key/variable so it resolves to a function.","Wrap non-function integrations: introJs().onSkip(() => analytics.track('skip')).","Default optional handlers with a no-op function.","Type-check before registering to avoid the throw entirely."],"exampleFix":"// before\nintroJs().onSkip(analytics.track); // if track is undefined at this point\n// after\nintroJs().onSkip(() => analytics.track('tour_skipped'));","handlingStrategy":"validation","validationCode":"if (typeof skipCb !== 'function') { throw new TypeError('onSkip expects a function, got ' + typeof skipCb); }\nintroJs().onSkip(skipCb);","typeGuard":"function isFn(v: unknown): v is () => void { return typeof v === 'function'; }","tryCatchPattern":"try {\n  tour.onSkip(cb);\n} catch (e) {\n  if (e.message.includes('onskip was not a function')) {\n    tour.onSkip(() => {});\n  } else { throw e; }\n}","preventionTips":["Wrap library integrations (analytics) in an arrow function","Verify telemetry callbacks are configured before tour setup","Use TypeScript to enforce callback parameter types","Never pass objects/strings where the setter expects a function"],"tags":["callbacks","type-validation","api-misuse"],"backgroundTag":"callback-not-a-function","analyzedSha":"e5517e6a24e0530f87885af9fb2a69bafd1d4a6b","analyzedAt":"2026-08-31T22:12:26.007Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}