usablica/intro.js · error
Provided callback for onAfterChange was not a function
Error message
Provided callback for onAfterChange was not a function
What it means
Tour class onAfterChange registers the callback run after each step change, stored in this.callbacks.afterChange. It throws this error when the argument is not a function, per the shared validation pattern across intro.js setter methods.
Source
Thrown at src/packages/tour/tour.ts:562
this.callbacks.change = callback;
return this;
}
/**
* @deprecated onafterchange is deprecated, please use onAfterChange instead.
*/
onafterchange(callback: introAfterChangeCallback) {
this.onAfterChange(callback);
}
/**
* Add a callback to be called after the tour changes steps
* @param {Function} callback callback function to be called
*/
onAfterChange(callback: introAfterChangeCallback) {
if (!isFunction(callback)) {
throw new Error("Provided callback for onAfterChange was not a function");
}
this.callbacks.afterChange = callback;
return this;
}
/**
* @deprecated oncomplete is deprecated, please use onComplete instead.
*/
oncomplete(callback: introCompleteCallback) {
return this.onComplete(callback);
}
/**
* Add a callback to be called when the tour is completed
* @param {Function} callback callback function to be called
*/
onComplete(callback: introCompleteCallback) {View on GitHub (pinned to e5517e6a24)
Solutions
- Pass a real function: introJs().onAfterChange(function(targetElement){ ... }).
- Fix the undefined source: correct the config key, import, or variable name.
- Coalesce with a default: introJs().onAfterChange(cfg.afterChange || (() => {})).
- Move registration into initialization code that runs after handlers are defined.
- Add a caller-side type guard before invoking the setter.
Example fix
// before introJs().onAfterChange(config.afterChange); // key is 'afterChangeCb' // after introJs().onAfterChange(config.afterChangeCb);
Defensive patterns
Strategy: validation
Validate before calling
const after = cfg.afterChangeCb;
if (typeof after !== 'function') { throw new TypeError('afterChangeCb must be a function'); }
introJs().onAfterChange(after); Type guard
const isCallable = (v: unknown): v is () => void => typeof v === 'function';
Try / catch
try {
intro().onAfterChange(cb);
} catch (e) {
if (e.message.includes('onAfterChange was not a function')) {
console.error('onAfterChange callback invalid:', cb);
intro().onAfterChange(() => {});
} else { throw e; }
} Prevention
- Verify config keys exist before destructuring into callbacks
- Provide no-op defaults for optional lifecycle callbacks
- Avoid passing minified/renamed exports indirectly
- Call intro.js setters after handler definitions execute
When it happens
Trigger: introJs().onAfterChange() called with undefined/null/non-function — e.g., a typo'd config lookup or a callback name string instead of the function reference.
Common situations: Copy-pasting old intro.js v0.x snippet styles; bundler tree-shaking removing an exported handler referenced by string; optional callbacks in strict config pipelines arriving undefined.
Related errors
- Provided callback for onhintsadded was not a function.
- Provided callback for onhintclick was not a function.
- Provided callback for onhintclose was not a function.
- Provided callback for onBeforeChange was not a function
- Provided callback for onChange was not a function.
AI-assisted analysis of usablica/intro.js@e5517e6a24 (2026-08-31).
Data as JSON: /api/errors/94aea3648f99768f.
Report an issue: GitHub.