dotnet/aspnetcore · error
The property '${identifier}' is not writable.
Error message
The property '${identifier}' is not writable. What it means
Thrown in the JSCallType.SetValue branch when isWritableProperty(parent, memberName) returns false (line 645). isWritableProperty checks the data/accessor descriptor's 'writable' flag or presence of a 'set'; missing properties and read-only properties (e.g. frozen objects, getter-only accessors, built-in constants) are not writable.
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 294cab2f9b)
Solutions
- Check Object.getOwnPropertyDescriptor; if writable is false or only a getter exists, do not write directly.
- Expose a setter function in a JS shim and call it instead.
- Make the target object extensible / use a mutable container.
- Pick a different, writable property to hold the value.
Example fix
// before
await JS.InvokeVoidAsync("window.myConfig", newValue); // read-only
// after
// shim.js
let _cfg;
export function setConfig(v) { _cfg = v; }
export function getConfig() { return _cfg; }
// C#: await JS.InvokeVoidAsync("shim.setConfig", newValue); Defensive patterns
Strategy: validation
Validate before calling
// shim: safe set
export function setProp(obj, k, v) {
let o = obj;
while (o) { const d = Object.getOwnPropertyDescriptor(o, k); if (d) { if (!d.writable && !d.set) throw new TypeError(`${k} read-only`); break; } o = Object.getPrototypeOf(o); }
obj[k] = v;
} Type guard
function isWritable(o:any, k:string):boolean {
let cur = o;
while (cur) { const d = Object.getOwnPropertyDescriptor(cur, k); if (d) return !!d.writable || !!d.set; cur = Object.getPrototypeOf(cur); }
return Object.isExtensible(o);
} Try / catch
try { await JS.InvokeVoidAsync('obj.prop', val); } catch (e) { if (/not writable/i.test(e.message)) { /* use setter shim */ } else throw e; } Prevention
- Do not write to known read-only DOM properties; use setter functions.
- Avoid mutating frozen/sealed exports.
- Expose explicit setter functions in shims for mutable configuration.
When it happens
Trigger: Writing to a read-only property (e.g. 'window.undefined', a frozen object's field), a getter-only accessor, or a property that doesn't exist yet on a non-extensible object. Also writing to a property whose prototype descriptor is configurable:false writable:false.
Common situations: Trying to assign to a DOM read-only property; mutating a frozen/sealed export; version change that made a property read-only; SSR where the global is a stub.
Related errors
- The property '${identifier}' is not defined or is not readab
- Cannot create a JSObjectReference from the value '${jsObject
- Cannot create a JSStreamReference from the value '${streamRe
- Supplied value is not a typed array or blob.
- Cannot create a JSStreamReference from the value '${streamRe
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/347cb6d3821b5cf3.
Report an issue: GitHub.