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
InterceptProperty redefines a property with a getter/setter wrapper to run hooks; this is only possible for configurable properties. When the property already exists (directly or inherited) and its descriptor reports configurable:false, the library refuses to intercept it and throws instead of silently failing to install hooks.
Source
Thrown at packages/dev/inspector-v2/src/instrumentation/propertyInstrumentation.ts:85
const ownerAndDescriptor = GetPropertyDescriptor(target, propertyKey);
// If the property does not exist, we'll define one transiently directly on the target object.
const [propertyOwner, propertyDescriptor] = ownerAndDescriptor ?? [
target,
{
configurable: true,
enumerable: true,
writable: true,
value: undefined,
},
];
if (!ownerAndDescriptor) {
Reflect.defineProperty(propertyOwner, propertyKey, propertyDescriptor);
} else {
// If the property is not configurable, it cannot be intercepted.
if (!propertyDescriptor.configurable) {
throw new Error(`Property "${propertyKey.toString()}" of object "${target}" is not configurable.`);
}
// If the property is not writable, it cannot be intercepted, but it cannot be mutated anyway so there is no need to intercept it.
if (IsPropertyReadonly(propertyDescriptor)) {
return {
dispose: () => {},
};
}
}
// 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);
View on GitHub (pinned to 0592b347b8)
Solutions
- Verify with Object.getOwnPropertyDescriptor(owner, key).configurable before watching; skip non-configurable keys.
- Avoid Object.freeze/seal on objects whose properties you want to watch.
- If you control the definition, define the property with configurable:true.
- Watch an owning wrapper object or use a Proxy around the target instead of intercepting the property directly.
- If the property is readonly, note InterceptProperty silently returns a no-op disposable; only configurable but writable:false paths throw here.
Example fix
// before
const state = Object.freeze({ value: 1 });
InterceptProperty(state, "value", { afterSet: log }); // throws
// after
const state = { value: 1 }; // keep configurable
const d = InterceptProperty(state, "value", { afterSet: log });
d.dispose(); Defensive patterns
Strategy: validation
Validate before calling
function isInterceptable(target: object, key: PropertyKey): boolean {
let owner: object | null = target;
while (owner) {
const d = Reflect.getOwnPropertyDescriptor(owner, key);
if (d) return d.configurable === true;
owner = Reflect.getPrototypeOf(owner);
}
return true; // nonexistent props are created transiently
}
if (!isInterceptable(obj, "value")) throw new Error("skip interception"); Type guard
function isConfigurableProperty(target: object, key: PropertyKey): boolean {
const d = Reflect.getOwnPropertyDescriptor(target, key);
return d ? d.configurable : true;
} Try / catch
let disposable: IDisposable;
try {
disposable = InterceptProperty(obj, key, hooks);
} catch (e) {
if (e instanceof Error && /is not configurable/.test(e.message)) {
disposable = { dispose: () => {} }; // gracefully skip
} else throw e;
} Prevention
- Check descriptor.configurable before watching any property.
- Do not freeze/seal objects you intend to instrument.
- Prefer intercepting plain state objects over built-ins (Math, DOM, window.location).
- If you define properties yourself, always set configurable:true on instrumentable ones.
- Treat TypeScript readonly/const-asserted object fields as likely non-configurable at runtime after hardening.
When it happens
Trigger: Calling InterceptProperty (directly or via watchProperty) on a property declared with configurable:false — e.g. class methods/fields using decorators that seal them, frozen objects, built-in objects like Math/JSON properties, or properties created via Object.defineProperty without configurable:true.
Common situations: Watching properties on frozen state objects, on built-in host objects (DOM elements, Math, window.location), on TypeScript 'readonly' fields emitted with writable:false plus configurable:false, or third-party objects hardened by libraries like @ungap or Immer.
Related errors
- Failed to define new property "${propertyKey.toString()}" on
- Failed to restore original property descriptor "${propertyKe
- Property "${propertyKey.toString()}" of object "${target}" i
- Property "${propertyKey.toString()}" of object "${target}" i
- Failed to delete transient function "${propertyKey.toString(
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/66d972a6a04159e4.
Report an issue: GitHub.