BabylonJS/Babylon.js · error

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

Error message

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

What it means

Function instrumentation works by redefining the property on the target with Reflect.defineProperty, which is only possible for configurable properties. If Reflect.getOwnPropertyDescriptor returns a descriptor whose configurable flag is false, the property is immutable and the library refuses to intercept it with this error. This prevents silently failing to swap the function.

Source

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

): 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()));
    }

    // Get or create the hooks array for the property key.
    let hooksForKey = hooksMap.get(propertyKey);
    if (!hooksForKey) {
        hooksMap.set(propertyKey, (hooksForKey = []));
        if (

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Intercept a configurable wrapper: create your own object whose method delegates to the original and intercept that instead.
  2. Unfreeze/clone the object: const copy = {...target} (restores configurability for own props) and intercept the copy, then route callers through it.
  3. If you own the definition, change Object.defineProperty options to configurable: true (and writable: true).
  4. For prototype methods, intercept on the prototype only if that descriptor is configurable; otherwise wrap at the call site.

Example fix

// before
Object.defineProperty(obj, 'play', { value: fn, configurable: false });
InterceptFunction(obj, 'play', hooks);
// after
Object.defineProperty(obj, 'play', { value: fn, configurable: true, writable: true });
InterceptFunction(obj, 'play', hooks);
Defensive patterns

Strategy: validation

Validate before calling

function isConfigurable(target, propertyKey) {
  const d = Reflect.getOwnPropertyDescriptor(target, propertyKey);
  return !d || d.configurable;
}
if (!isConfigurable(target, 'play')) throw new TypeError('target.play is not configurable');

Type guard

function hasConfigurableDescriptor(target: object, key: PropertyKey): boolean {
  const d = Object.getOwnPropertyDescriptor(target, key);
  return d === undefined || d.configurable === true;
}

Try / catch

try {
  InterceptFunction(target, propertyKey, hooks);
} catch (e) {
  if (String((e as Error)?.message).includes('is not configurable')) {
    console.warn(`Skipping interception of ${String(propertyKey)}: non-configurable property`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling InterceptFunction on a property that was defined with configurable: false — e.g. built-ins like Function.prototype.call, methods defined via Object.defineProperty with configurable:false, frozen (Object.freeze) or sealed (Object.seal) objects, or class fields made non-configurable.

Common situations: Trying to hook native/built-in methods that are non-configurable in some engines; intercepting methods on objects passed through Object.freeze for immutability; instrumenting module exports or namespace objects; attempts to hook secure/hardened objects.

Related errors


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