{"record":{"id":"e1502cd514678198","repo":"nwjs/nw.js","slug":"menu-items-is-immutable","errorCode":null,"errorMessage":"Menu.items is immutable","messagePattern":"Menu\\.items is immutable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/api/menu/menu.js","lineNumber":43,"sourceCode":"function Menu(option) {\n  if (typeof option != 'object')\n    option = { type: 'contextmenu' };\n\n  if (option.type != 'contextmenu' && option.type != 'menubar')\n    throw new TypeError('Invalid menu type: ' + option.type);\n\n  this.type = option.type;\n  v8_util.setHiddenValue(this, 'items', []);\n  nw.allocateObject(this, option);\n}\nrequire('util').inherits(Menu, exports.Base);\n\nMenu.prototype.__defineGetter__('items', function() {\n  return v8_util.getHiddenValue(this, 'items');\n});\n\nMenu.prototype.__defineSetter__('items', function(val) {\n  throw new Error('Menu.items is immutable');\n});\n\nMenu.prototype.append = function(menu_item) {\n  if (v8_util.getConstructorName(menu_item) != 'MenuItem')\n    throw new TypeError(\"Menu.append() requires a valid MenuItem\");\n    \n  this.items.push(menu_item);\n  nw.callObjectMethod(this, 'Append', [ menu_item.id ]);\n};\n\nMenu.prototype.insert = function(menu_item, i) {\n  this.items.splice(i, 0, menu_item);\n  nw.callObjectMethod(this, 'Insert', [ menu_item.id, i ]);\n}\n\nMenu.prototype.remove = function(menu_item) {\n  var pos_hint = this.items.indexOf(menu_item);\n  nw.callObjectMethod(this, 'Remove', [ menu_item.id, pos_hint ]);","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/nwjs/nw.js/blob/e15da848e9e08e6e467532dae78995c6ad2f55ee/src/api/menu/menu.js#L25-L61","documentation":"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.","triggerScenarios":"Writing `menu.items = [item1, item2]`, `menu.items = []` (attempting to clear), or `menu.items.length = 0`. Any assignment to the property hits the throwing setter.","commonSituations":"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.","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."],"exampleFix":"// before\nmenu.items = [newItem1, newItem2]; // throws\n\n// after\nwhile (menu.items.length) menu.remove(menu.items[0]);\n[newItem1, newItem2].forEach(function (i) { menu.append(i); });","handlingStrategy":"validation","validationCode":"// Never assign menu.items. To clear:\nfunction clearMenu(menu) {\n  while (menu.items.length) menu.remove(menu.items[0]);\n}","typeGuard":null,"tryCatchPattern":"try { menu.items = next; }\ncatch (e) {\n  if (e instanceof Error && /immutable/.test(e.message)) {\n    while (menu.items.length) menu.remove(menu.items[0]);\n    next.forEach(function (i) { menu.append(i); });\n  } else throw e;\n}","preventionTips":["Treat menu.items as read-only.","Use append/insert/remove/removeAt for all mutations.","For a full reset, build a new nw.Menu."],"tags":["nwjs","menu","immutable","read-only","programming-error"],"backgroundTag":null,"analyzedSha":"e15da848e9e08e6e467532dae78995c6ad2f55ee","analyzedAt":"2026-08-13T04:15:35.452Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}