BabylonJS/Babylon.js · error
Failed to delete transient property descriptor "${propertyKe
Error message
Failed to delete transient property descriptor "${propertyKey.toString()}" on object "${target}". What it means
On final dispose, if the intercepted property did not exist on the target originally (it was inherited or newly transient), the library deletes the transient accessor with Reflect.deleteProperty so lookups fall back to the prototype chain. This error means the delete returned false, so the transient property remains on the object and shadows the prototype member.
Source
Thrown at packages/dev/inspector-v2/src/instrumentation/propertyInstrumentation.ts:168
if (hooksMap.size === 0) {
InterceptorHooksMaps.delete(target);
}
const shouldRestorePropertyDescriptor =
// If the property is owned by the target object, then we may have replaced an original property descriptor that needs to be restore.
propertyOwner === target &&
// But this is only the case if we found an existing property descriptor on the target object (hence the ownerAndDescriptor check),
// or if the property value is not undefined, in which case we still want to retain the value that was set.
(ownerAndDescriptor || target[propertyKey] !== undefined);
// Otherwise, the property was inherited through the prototype chain, and so we can simply delete it from the target object.
if (shouldRestorePropertyDescriptor) {
if (!Reflect.defineProperty(target, propertyKey, propertyDescriptor)) {
throw new Error(`Failed to restore original property descriptor "${propertyKey.toString()}" on object "${target}".`);
}
} else {
if (!Reflect.deleteProperty(target, propertyKey)) {
throw new Error(`Failed to delete transient property descriptor "${propertyKey.toString()}" on object "${target}".`);
}
}
}
isDisposed = true;
}
},
};
}
View on GitHub (pinned to 0592b347b8)
Solutions
- Dispose all InterceptProperty disposables before freezing/sealing the target.
- Verify Object.isFrozen(target) before disposal; unfreeze or rebuild if frozen.
- Ensure no other code redefines the transient property to configurable:false while hooked.
- Capture the state and rebuild the object if deleteProperty keeps failing.
- As a workaround, set the transient property to undefined instead of relying on deletion, then recreate the object cleanly.
Example fix
// before
const d = InterceptProperty(instance, "inheritedProp", { afterSet: log });
Object.freeze(instance);
d.dispose(); // throws
// after
const d = InterceptProperty(instance, "inheritedProp", { afterSet: log });
d.dispose();
Object.freeze(instance); Defensive patterns
Strategy: try-catch
Validate before calling
// before dispose
const d = Reflect.getOwnPropertyDescriptor(target, key);
if (d && !d.configurable) console.warn("transient property cannot be deleted; defer or rebuild");
if (Object.isFrozen(target)) console.warn("frozen target; deleteProperty will fail"); Type guard
function canDeleteProperty(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 property descriptor/.test(e.message)) {
try { delete (target as any)[key]; } catch { /* recreate object */ }
} else throw e;
} Prevention
- Freeze/seal objects only after all property watchers are disposed.
- Track whether a property was transient (created by interception) and verify it is still configurable at teardown.
- Avoid interleaving other interceptors that might make the transient property non-configurable.
- If deletion fails repeatedly, rebuild the object from a state snapshot.
- Log dispose errors to detect objects left shadowing prototype members.
When it happens
Trigger: Disposing InterceptProperty where the property was transient, but the target became frozen/sealed (non-configurable own property cannot be deleted), or the transient property was redefined with configurable:false while hooked.
Common situations: Freezing a scene/store object while property watchers are active; teardown ordering where a hardening step runs before disposals; another interceptor converting the transient accessor to a non-configurable one.
Related errors
- Failed to delete transient function "${propertyKey.toString(
- Failed to restore original 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/55bf0fa7fc02bed5.
Report an issue: GitHub.