nwjs/nw.js · error · Error
Menu.items is immutable
Error message
Menu.items is immutable
What it means
Menu defines `items` as a read-only managed array (a hidden value populated by append/insert). Assigning to menu.items triggers a setter that always throws a plain Error. You must mutate the list through append/insert/remove/removeAt, which keep the native side in sync.
Source
Thrown at src/api/menu/menu.js:43
function Menu(option) {
if (typeof option != 'object')
option = { type: 'contextmenu' };
if (option.type != 'contextmenu' && option.type != 'menubar')
throw new TypeError('Invalid menu type: ' + option.type);
this.type = option.type;
v8_util.setHiddenValue(this, 'items', []);
nw.allocateObject(this, option);
}
require('util').inherits(Menu, exports.Base);
Menu.prototype.__defineGetter__('items', function() {
return v8_util.getHiddenValue(this, 'items');
});
Menu.prototype.__defineSetter__('items', function(val) {
throw new Error('Menu.items is immutable');
});
Menu.prototype.append = function(menu_item) {
if (v8_util.getConstructorName(menu_item) != 'MenuItem')
throw new TypeError("Menu.append() requires a valid MenuItem");
this.items.push(menu_item);
nw.callObjectMethod(this, 'Append', [ menu_item.id ]);
};
Menu.prototype.insert = function(menu_item, i) {
this.items.splice(i, 0, menu_item);
nw.callObjectMethod(this, 'Insert', [ menu_item.id, i ]);
}
Menu.prototype.remove = function(menu_item) {
var pos_hint = this.items.indexOf(menu_item);
nw.callObjectMethod(this, 'Remove', [ menu_item.id, pos_hint ]);View on GitHub (pinned to e15da848e9)
Solutions
- To clear, loop and call menu.remove(item) (or removeAt) for each entry.
- To rebuild, remove all existing items then append the new ones.
- If you need a fresh set, construct a new nw.Menu rather than reassigning items.
Example fix
// before
menu.items = [newItem1, newItem2]; // throws
// after
while (menu.items.length) menu.remove(menu.items[0]);
[newItem1, newItem2].forEach(function (i) { menu.append(i); }); Defensive patterns
Strategy: validation
Validate before calling
// Never assign menu.items. To clear:
function clearMenu(menu) {
while (menu.items.length) menu.remove(menu.items[0]);
} Try / catch
try { menu.items = next; }
catch (e) {
if (e instanceof Error && /immutable/.test(e.message)) {
while (menu.items.length) menu.remove(menu.items[0]);
next.forEach(function (i) { menu.append(i); });
} else throw e;
} Prevention
- Treat menu.items as read-only.
- Use append/insert/remove/removeAt for all mutations.
- For a full reset, build a new nw.Menu.
When it happens
Trigger: Writing `menu.items = [item1, item2]`, `menu.items = []` (attempting to clear), or `menu.items.length = 0`. Any assignment to the property hits the throwing setter.
Common situations: Developers try to bulk-replace or clear a menu by reassigning items (idiomatic for normal arrays). Refactoring that treats items as a normal array property. Attempting to reset state on window reactivation.
Related errors
- 'type' is immutable at runtime
- Menu.items is immutable
- It's forbidden to instantialize a Base class.
- Invalid menu type: {option.type}
- Menu.append() requires a valid MenuItem
AI-assisted analysis of nwjs/nw.js@e15da848e9 (2026-08-13).
Data as JSON: /api/errors/e1502cd514678198.
Report an issue: GitHub.