BabylonJS/Babylon.js · error

Property "${propertyKey.toString()}" of object "${target}" i

Error message

Property "${propertyKey.toString()}" of object "${target}" is not a function.

What it means

InterceptFunction replaces a property on a target object with an intercepting proxy function, so it requires the property to already be a function. Before instrumenting, it reads the property via Reflect.get and throws this error if the resolved value is not callable. This guards against instrumenting data properties, undefined keys, or typos in the property name.

Source

Thrown at packages/dev/inspector-v2/src/instrumentation/functionInstrumentation.ts:39

 * @returns A disposable that removes the hooks when disposed and returns the object to its original state.
 */
// This overload only matches when K is a specific literal key (not a union like keyof T)
export function InterceptFunction<T extends object, K extends keyof T>(
    target: T,
    propertyKey: string extends K ? never : number extends K ? never : symbol extends K ? never : K,
    hooks: NonNullable<T[K]> extends (...args: infer Args) => unknown ? FunctionHooks<Args> : FunctionHooks
): IDisposable;
// Fallback overload for generic/dynamic cases where the function type cannot be inferred
export function InterceptFunction<T extends object>(target: T, propertyKey: keyof T, hooks: FunctionHooks): IDisposable;
/** @internal */
export function InterceptFunction<T extends object>(target: T, propertyKey: keyof T, hooks: FunctionHooks): IDisposable {
    if (!hooks.afterCall) {
        throw new Error("At least one hook must be provided.");
    }

    const originalFunction = Reflect.get(target, propertyKey, target) as (...args: any) => any;
    if (typeof originalFunction !== "function") {
        throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is not a function.`);
    }

    // Make sure the property is configurable and writable, otherwise it is immutable and cannot be intercepted.
    const propertyDescriptor = Reflect.getOwnPropertyDescriptor(target, propertyKey);
    if (propertyDescriptor) {
        if (!propertyDescriptor.configurable) {
            throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is not configurable.`);
        }

        if (propertyDescriptor.writable === false || (propertyDescriptor.writable === undefined && !propertyDescriptor.set)) {
            throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is readonly.`);
        }
    }

    // Get or create the hooks map for the target object.
    let hooksMap = InterceptorHooksMaps.get(target);
    if (!hooksMap) {
        InterceptorHooksMaps.set(target, (hooksMap = new Map()));

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Verify the exact property name exists on the target at interception time (log Object.keys(target) / console.log(target)).
  2. Fix typos and confirm the property is a function (typeof target[key] === 'function') before calling InterceptFunction.
  3. If the property is assigned asynchronously, defer interception until after assignment (e.g. await initialization, or intercept on the prototype where the method is defined).
  4. If the value is data, use a property/value interception mechanism instead of function instrumentation.

Example fix

// before
InterceptFunction(player, 'paly' /* typo */, hooks);
// after
if (typeof player.play === 'function') {
  InterceptFunction(player, 'play', hooks);
}
Defensive patterns

Strategy: validation

Validate before calling

function canInterceptFunction(target, propertyKey) {
  const value = Reflect.get(target, propertyKey, target);
  return typeof value === 'function';
}
if (!canInterceptFunction(target, 'play')) throw new TypeError('target.play is not a function');

Type guard

function isInterceptableFunction(target: object, key: PropertyKey): boolean {
  return typeof (target as any)[key] === 'function';
}

Try / catch

try {
  InterceptFunction(target, propertyKey, hooks);
} catch (e) {
  if (String((e as Error)?.message).includes('is not a function')) {
    console.warn(`Cannot intercept ${String(propertyKey)}: not a function on`, target);
    return null; // skip instrumentation gracefully
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling InterceptFunction(target, propertyKey, hooks) (directly or via useInterceptObservable/hookMainSoundTrack/playHook/stopHook/animateHook/setSelectedItem) when target[propertyKey] is undefined, a data value, a getter returning a non-function, or the property name is misspelled.

Common situations: Typo in the method name; instrumenting an object whose API changed between library versions so the method no longer exists; trying to intercept a plain data field or a property that is only assigned later (asynchronously) before it is set; targeting a module namespace object or a frozen/bound copy where the method lives on the prototype under a different key.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/c8e80ebac83b1098. Report an issue: GitHub.