nwjs/nw.js · error · Error
'type' is immutable at runtime
Error message
'type' is immutable at runtime
What it means
MenuItem defines a `type` setter that unconditionally throws a plain Error — type is fixed at construction and cannot be changed at runtime. The getter reads from the hidden option object via handleGetter. Reassigning menuItem.type (even to the same value) trips the setter.
Source
Thrown at src/api/menuitem/menuitem.js:103
if (!option.hasOwnProperty('icon'))
option.shadowIcon = '';
if (!option.hasOwnProperty('tooltip'))
option.tooltip = '';
if (!option.hasOwnProperty('enabled'))
option.enabled = true;
if (!option.hasOwnProperty('key'))
option.key = "";
if (!option.hasOwnProperty('modifiers'))
option.modifiers = "";
}
require('util').inherits(MenuItem, exports.Base);
MenuItem.prototype.__defineGetter__('type', function() {
return this.handleGetter('type');
});
MenuItem.prototype.__defineSetter__('type', function() {
throw new Error("'type' is immutable at runtime");
});
MenuItem.prototype.__defineGetter__('label', function() {
return this.handleGetter('label');
});
MenuItem.prototype.__defineSetter__('label', function(val) {
this.handleSetter('label', 'SetLabel', String, val);
});
MenuItem.prototype.__defineGetter__('icon', function() {
return this.handleGetter('shadowIcon');
});
MenuItem.prototype.__defineSetter__('icon', function(val) {
v8_util.getHiddenValue(this, 'option').shadowIcon = String(val);
var real_path = val == '' ? '' : nw.getAbsolutePath(val);
this.handleSetter('icon', 'SetIcon', String, real_path);View on GitHub (pinned to e15da848e9)
Solutions
- Create a new MenuItem with the desired type and replace the old one in the menu.
- If you only need toggle UI, use type 'checkbox' from the start and flip the `checked` property.
- Avoid generic property-copy loops that write back `type`.
Example fix
// before
item.type = 'checkbox'; // throws
// after
menu.remove(item);
var toggler = new nw.MenuItem({ type: 'checkbox', label: item.label, checked: true, click: item.click });
menu.append(toggler); Defensive patterns
Strategy: validation
Validate before calling
// type is set-once: never reassign it.
function changeItemType(menu, item, newType) {
var opt = { type: newType, label: item.label, click: item.click };
if (item.icon) opt.icon = item.icon;
var next = new nw.MenuItem(opt);
var pos = menu.items.indexOf(item);
menu.remove(item);
menu.insert(next, pos);
} Try / catch
try { item.type = newType; }
catch (e) {
if (e instanceof Error && /immutable/.test(e.message)) {
throw new Error('Cannot change item.type at runtime; rebuild the item.');
} throw e;
} Prevention
- Treat `type` as read-only after construction.
- Pick the correct type up front.
- Avoid generic property-copy loops over menu items.
When it happens
Trigger: Any assignment to `menuItem.type`, e.g. `item.type = 'checkbox'` or `item.type = item.type`. Also attempts to toggle a normal item into a checkbox at runtime.
Common situations: Developers try to mutate item kind dynamically (e.g., switching between normal and checkbox based on state). Code that defensively reassigns properties after load. Copy/restore patterns that iterate and write all properties.
Related errors
- Menu.items is immutable
- 'type' is immutable at runtime
- It's forbidden to instantialize a Base class.
- Menu.append() requires a valid MenuItem
- Invalid option.
AI-assisted analysis of nwjs/nw.js@e15da848e9 (2026-08-13).
Data as JSON: /api/errors/3dc22b0f2041eeb3.
Report an issue: GitHub.