BabylonJS/Babylon.js · error
Failed to delete transient function "${propertyKey.toString(
Error message
Failed to delete transient function "${propertyKey.toString()}" on object "${target}". What it means
InterceptFunction temporarily replaces an inherited function by defining an own property on the target object. On dispose, when no descriptor existed on the target (the function was inherited), it tries Reflect.deleteProperty to restore the prototype-chain lookup. This error means that delete returned false, so the transient own property could not be removed and the object is left with the hooked wrapper still installed.
Source
Thrown at packages/dev/inspector-v2/src/instrumentation/functionInstrumentation.ts:105
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);
}
if (propertyDescriptor) {
// If we have a property descriptor, it means the property was defined directly on the target object,
// in which case we replaced it and the original property descriptor needs to be restored.
if (!Reflect.defineProperty(target, propertyKey, propertyDescriptor)) {
throw new Error(`Failed to restore original function "${propertyKey.toString()}" on object "${target}".`);
}
} else {
// Otherwise, the property was inherited through the prototype chain, and so we can simply delete it from
// the target object to allow it to fall back to the prototype chain as it did originally.
if (!Reflect.deleteProperty(target, propertyKey)) {
throw new Error(`Failed to delete transient function "${propertyKey.toString()}" on object "${target}".`);
}
}
}
isDisposed = true;
}
},
};
}
View on GitHub (pinned to 0592b347b8)
Solutions
- Check whether the target was frozen/sealed or the property became non-configurable between InterceptFunction and dispose; avoid freezing objects under instrumentation.
- Dispose interceptors before applying Object.freeze/seal to the target object.
- Ensure no other library redefines the intercepted property while the hook is active.
- Wrap dispose in try/catch and, if it throws, manually restore the object (delete the own property or re-create the target).
- As a last resort, discard/rebuild the target object since its cleanup failed.
Example fix
// before
Object.freeze(camera);
const d = InterceptFunction(camera, "render", { afterCall: log });
d.dispose(); // throws on dispose
// after
const d = InterceptFunction(camera, "render", { afterCall: log });
d.dispose();
Object.freeze(camera); Defensive patterns
Strategy: try-catch
Validate before calling
// before disposing
if (Object.isFrozen(target) || !Object.isExtensible(target)) {
console.warn("Target frozen; deferred disposal of function interceptor");
}
const own = Reflect.getOwnPropertyDescriptor(target, key);
if (own && !own.configurable) console.warn("Transient function prop became non-configurable"); Type guard
function isDisposableTarget(target: object, key: PropertyKey): boolean {
if (Object.isFrozen(target)) return false;
const d = Reflect.getOwnPropertyDescriptor(target, key);
return !d || d.configurable;
} Try / catch
try {
disposable.dispose();
} catch (e) {
if (e instanceof Error && /Failed to delete transient function/.test(e.message)) {
try { delete (target as any)[key]; } catch { /* recreate target */ }
} else throw e;
} Prevention
- Never freeze or seal objects that are being intercepted.
- Dispose interceptors in LIFO order during teardown before hardening steps.
- Capture whether the property was originally own or inherited before intercepting.
- Watch for other monkey-patching libraries touching the same property.
- Log dispose failures instead of letting them break teardown loops.
When it happens
Trigger: Calling InterceptFunction on a function inherited from the prototype chain, then disposing the returned IDisposable when the target has since been frozen (Object.freeze) or sealed, or the own property was redefined as non-configurable by other code while the hook was active.
Common situations: Intercepting engine/built-in prototype methods during hot-reload or inspector tooling, or disposing interceptors in tests after other instrumentation (e.g. a second interceptor or a mock framework) rewrote the property with configurable:false. Also happens with Object.freeze(target) applied mid-session.
Related errors
- Failed to restore original property descriptor "${propertyKe
- Failed to delete transient property descriptor "${propertyKe
- Failed to restore original function "${propertyKey.toString(
- Property "${propertyKey.toString()}" of object "${target}" i
- Failed to define new property "${propertyKey.toString()}" on
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/b1b8c5e58bcaf0c4.
Report an issue: GitHub.