usablica/intro.js · error

Provided callback for onBeforeChange was not a function

Error message

Provided callback for onBeforeChange was not a function

What it means

Tour class onBeforeChange registers a callback executed before the tour switches steps, stored in this.callbacks.beforeChange. It throws this error when the argument fails the isFunction check, guaranteeing the internal invocation is always safe.

Source

Thrown at src/packages/tour/tour.ts:520

    }

    return this;
  }

  /**
   * @deprecated onbeforechange is deprecated, please use onBeforeChange instead.
   */
  onbeforechange(callback: introBeforeChangeCallback) {
    return this.onBeforeChange(callback);
  }

  /**
   * Add a callback to be called before the tour changes steps
   * @param {Function} callback callback function to be called
   */
  onBeforeChange(callback: introBeforeChangeCallback) {
    if (!isFunction(callback)) {
      throw new Error(
        "Provided callback for onBeforeChange was not a function"
      );
    }

    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

View on GitHub (pinned to e5517e6a24)

Solutions

  1. Pass an explicit function: introJs().onBeforeChange(function(targetElement){ ... }).
  2. Fix the source of the undefined value (config key typo, missing import, wrong prop name).
  3. Defer registration until the handler exists (e.g., in a useEffect/mounted hook).
  4. Check TypeScript optionality — supply a default no-op function for optional callbacks.
  5. Wrap in try/catch during setup to fail fast with clearer context.

Example fix

// before
introJs().onBeforeChange(props.beforeChange); // undefined on first render
// after
useEffect(() => {
  if (typeof props.beforeChange === 'function') {
    introJs().onBeforeChange(props.beforeChange);
  }
}, []);
Defensive patterns

Strategy: type-guard

Validate before calling

const safeBeforeChange = typeof cfg.beforeChange === 'function' ? cfg.beforeChange : () => {};
introJs().onBeforeChange(safeBeforeChange);

Type guard

const isFn = (v: unknown): v is (el: Element) => void => typeof v === 'function';

Try / catch

try {
  tour.onBeforeChange(cb);
} catch (e) {
  if (e.message.startsWith('Provided callback for onBeforeChange')) {
    tour.onBeforeChange(() => {});
  } else { throw e; }
}

Prevention

When it happens

Trigger: introJs().onBeforeChange() or onBeforeChange(config.beforeChange) where the value is undefined, null, or non-function; note this variant's message has no trailing period.

Common situations: Framework integrations (React/Vue) passing state values that are undefined on first render; passing a hook/observer object instead of the callback; version migration where the callback name in a wrapper lib changed.

Related errors


AI-assisted analysis of usablica/intro.js@e5517e6a24 (2026-08-31). Data as JSON: /api/errors/2b5b8fe6a78ceb76. Report an issue: GitHub.