usablica/intro.js · error
Provided callback for onChange was not a function.
Error message
Provided callback for onChange was not a function.
What it means
Tour class onChange registers the per-step-change callback into this.callbacks.change. It validates the argument with isFunction and throws when it is not a function, so the tour's internal call site can invoke it unconditionally.
Source
Thrown at src/packages/tour/tour.ts:542
this.callbacks.beforeChange = callback;
return this;
}
/**
* @deprecated onchange is deprecated, please use onChange instead.
*/
onchange(callback: introChangeCallback) {
this.onChange(callback);
}
/**
* Add a callback to be called when the tour changes steps
* @param {Function} callback callback function to be called
*/
onChange(callback: introChangeCallback) {
if (!isFunction(callback)) {
throw new Error("Provided callback for onChange was not a function.");
}
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) {View on GitHub (pinned to e5517e6a24)
Solutions
- Pass a function: introJs().onChange(function(targetElement){ ... }).
- Verify typeof the argument is 'function' right before the call and trace back why it isn't.
- Register callbacks after module/config initialization completes.
- Use a no-op fallback: introJs().onChange(config.onChange || function(){}).
- Catch the error to log which setup step was misconfigured.
Example fix
// before introJs().onChange(await loadHandler()); // Promise, not function // after const handler = await loadHandler(); introJs().onChange(() => handler());
Defensive patterns
Strategy: validation
Validate before calling
if (typeof changeCb !== 'function') changeCb = () => {};
introJs().onChange(changeCb); Type guard
function isFunction(v: unknown): v is Function { return typeof v === 'function'; } Try / catch
try {
introJs().onChange(cb);
} catch (e) {
if (/onChange was not a function/.test(e.message)) {
introJs().onChange(() => {});
} else { throw e; }
} Prevention
- Pass functions, never Promises or their results
- Assign handlers before introJs() setup runs
- Use consistent naming between config keys and variables
- Lint for calls to onChange/on* with non-identifier arguments
When it happens
Trigger: introJs().onChange() with no argument or a non-function value (undefined variable, Promise, object) — commonly from an options object wired to the wrong key.
Common situations: Passing the result of an async function (a Promise) instead of a function; SSR frameworks where the handler module isn't loaded; renaming handlers and missing one call site.
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 onAfterChange was not a function
AI-assisted analysis of usablica/intro.js@e5517e6a24 (2026-08-31).
Data as JSON: /api/errors/f4e3df92f736df82.
Report an issue: GitHub.