dotnet/aspnetcore · error · Error
The property ' ' is not writable.
Error message
The property '${identifier}' is not writable. What it means
Thrown by wrapJSCallAsFunction() in the SetValue case when isWritableProperty() returns false. A SetValue operation (.NET assigning a value to a JS property via interop) requires the property to be writable, have a setter, or be addable on an extensible object. Read-only properties, frozen objects, and write-only-missing scenarios are rejected.
Solutions
- Check the descriptor: Object.getOwnPropertyDescriptor(window.myObj, 'prop').writable.
- If read-only by design, expose a setter or a method that mutates internally.
- Remove Object.freeze / Object.preventExtensions on the target if mutation is intended.
Example fix
// before (JS)
Object.defineProperty(myObj, 'config', { value: 1, writable: false });
// C#: await JS.InvokeVoidAsync("myObj.config", 2); // throws
// after (JS)
Object.defineProperty(myObj, 'config', { value: 1, writable: true }); Defensive patterns
Strategy: validation
Validate before calling
function isWritable(obj, prop) { if (!(prop in obj)) return Object.isExtensible(obj); let o = obj; while (o) { const d = Object.getOwnPropertyDescriptor(o, prop); if (d) return (d.writable === true) || (typeof d.set === 'function'); o = Object.getPrototypeOf(o); } return false; } Type guard
function isWritableMember(obj: any, prop: string): boolean { if (!(prop in obj)) return Object.isExtensible(obj); let o: any = obj; while (o) { const d = Object.getOwnPropertyDescriptor(o, prop); if (d) return d.writable === true || typeof d.set === 'function'; o = Object.getPrototypeOf(o); } return false; } Try / catch
try { await JS.InvokeVoidAsync("myObj.config", value); } catch (JSException e) when (e.Message.Contains("is not writable")) { /* check descriptor.writable, freeze, or getter-only */ } Prevention
- Check the property descriptor's writable flag before assigning via interop.
- Avoid Object.freeze/preventExtensions on objects that .NET must mutate.
- Expose setters or mutating methods for encapsulated state.
When it happens
Trigger: .NET calls JS.InvokeVoidAsync('myObj.readOnlyProp', value) to set a property that is defined with writable:false, has only a getter, lives on a frozen/sealed object, or is on a non-extensible object without an existing data property.
Common situations: Assigning to a getter-only property; assigning to a property on Object.freeze'd objects; trying to add a new property to a non-extensible object; legacy code that mutated internals now locked down.
Related errors
- The property ' ' is not defined or is not readable.
- Could not find ' ' (' ' was undefined).
- The value ' ' is not a function.
- Byte array index ' ' does not exist.
- Cannot create a JSObjectReference from the value
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/347cb6d3821b5cf3.
Report an issue: GitHub.
Appendix: source
Thrown at src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts:646
}
throw new Error(`The value '${identifier}' is not a function.`);
case JSCallType.ConstructorCall:
const ctor = parent[memberName];
if (ctor instanceof Function) {
const bound = ctor.bind(parent);
return (...args: any[]) => new bound(...args);
}
throw new Error(`The value '${identifier}' is not a function.`);
case JSCallType.GetValue:
if (!isReadableProperty(parent, memberName)) {
throw new Error(`The property '${identifier}' is not defined or is not readable.`);
}
return () => parent[memberName];
case JSCallType.SetValue:
if (!isWritableProperty(parent, memberName)) {
throw new Error(`The property '${identifier}' is not writable.`);
}
return (...args: any[]) => parent[memberName] = args[0];
}
}
function isReadableProperty(obj: any, propName: string) {
// Return false for missing property.
if (!(propName in obj)) {
return false;
}
// If the property is present we examine its descriptor, potentially needing to walk up the prototype chain.
while (obj !== undefined) {
const descriptor = Object.getOwnPropertyDescriptor(obj, propName);
if (descriptor) {
// Return true for data property
if (descriptor.hasOwnProperty("value")) {View on GitHub (pinned to 3600ca084e)