BabylonJS/Babylon.js · error

Failed to define new function "${propertyKey.toString()}" on

Error message

Failed to define new function "${propertyKey.toString()}" on object "${target}".

What it means

After validating the property, InterceptFunction installs the interceptor by redefining the property with Reflect.defineProperty; the property is only considered intercepted if that call returns true. If the redefinition fails, this error is thrown. This usually means the descriptor check passed but the engine still refused the redefine (e.g. Proxy invariants, exotic objects, or a change between the descriptor check and the define).

Source

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

    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 (
            // Replace the function with a new one that calls the hooks in addition to the original function.
            !Reflect.set(target, propertyKey, function (this: unknown, ...args: unknown[]) {
                const result = Reflect.apply(originalFunction, this, args);
                for (const { afterCall } of hooksForKey!) {
                    afterCall?.(...args);
                }
                return result;
            })
        ) {
            throw new Error(`Failed to define new function "${propertyKey.toString()}" on object "${target}".`);
        }
    }
    hooksForKey.push(hooks as FunctionHooks<unknown[]>);

    let isDisposed = false;
    return {
        dispose: () => {
            if (!isDisposed) {
                // Remove the hooks from the hooks array for the property key.
                hooksForKey.splice(hooksForKey.indexOf(hooks), 1);

                // If there are no more hooks for the property key, remove the property from the hooks map.
                if (hooksForKey.length === 0) {
                    hooksMap.delete(propertyKey);

                    // If there are no more hooks for the target object, remove the hooks map from the WeakMap.
                    if (hooksMap.size === 0) {
                        InterceptorHooksMaps.delete(target);

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Intercept the underlying raw object, not a Proxy wrapper around it.
  2. Re-check that the property is still configurable/writable immediately before intercepting; avoid racing other code that redefines it.
  3. For builtin/host objects, wrap them in your own plain object with delegating methods and intercept that.
  4. Catch this error and fall back to manual instrumentation (call hooks.afterCall explicitly at the call site).

Example fix

// before
InterceptFunction(proxyWrappedPlayer, 'play', hooks); // defineProperty fails on proxy invariants
// after
InterceptFunction(rawPlayer, 'play', hooks); // intercept the raw target, not the proxy
Defensive patterns

Strategy: try-catch

Validate before calling

function isPlainInterceptableTarget(target: object, key: PropertyKey): boolean {
  const d = Object.getOwnPropertyDescriptor(target, key);
  return (!d || (d.configurable && d.writable !== false)) && !Symbol.toStringTag; // also avoid proxies/exotic targets
}
// check before intercepting:
if (!isPlainInterceptableTarget(target, 'play')) throw new TypeError('target not safely redefinable');

Type guard

function isRawInterceptable(target: object, key: PropertyKey): boolean {
  if (typeof Proxy !== 'undefined') {
    try { Object.getOwnPropertyDescriptor(target, key); } catch { return false; } // proxies may throw on invariants
  }
  const d = Object.getOwnPropertyDescriptor(target, key);
  return !d || (d.configurable && d.writable !== false);
}

Try / catch

try {
  const handle = InterceptFunction(target, propertyKey, hooks);
  return handle;
} catch (e) {
  if (String((e as Error)?.message).includes('Failed to define new function')) {
    console.warn(`Redefinition failed for ${String(propertyKey)}; falling back to manual hooks`);
    return null; // call hooks.afterCall manually at the call site
  }
  throw e;
}

Prevention

When it happens

Trigger: Reflect.defineProperty(target, propertyKey, replacementDescriptor) returning false during InterceptFunction — e.g. the target is a Proxy whose invariant constraints reject the redefinition, the property changed between getOwnPropertyDescriptor and defineProperty, or the target is an exotic/builtin object that disallows redefining the property.

Common situations: Instrumenting objects behind a Proxy (invariant violations); hooking host/builtin objects (DOM, Node internals) with unusual internal slots; concurrent code redefining the same property mid-interception; intercepting properties on module namespace objects.

Related errors


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