{"record":{"id":"3dc22b0f2041eeb3","repo":"nwjs/nw.js","slug":"type-is-immutable-at-runtime","errorCode":null,"errorMessage":"'type' is immutable at runtime","messagePattern":"'type' is immutable at runtime","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/api/menuitem/menuitem.js","lineNumber":103,"sourceCode":"  if (!option.hasOwnProperty('icon'))\n    option.shadowIcon = '';\n  if (!option.hasOwnProperty('tooltip'))\n    option.tooltip = '';\n  if (!option.hasOwnProperty('enabled'))\n    option.enabled = true;\n  if (!option.hasOwnProperty('key'))\n    option.key = \"\";\n  if (!option.hasOwnProperty('modifiers'))\n    option.modifiers = \"\";\n}\nrequire('util').inherits(MenuItem, exports.Base);\n\nMenuItem.prototype.__defineGetter__('type', function() {\n  return this.handleGetter('type');\n});\n\nMenuItem.prototype.__defineSetter__('type', function() {\n  throw new Error(\"'type' is immutable at runtime\");\n});\n\nMenuItem.prototype.__defineGetter__('label', function() {\n  return this.handleGetter('label');\n});\n\nMenuItem.prototype.__defineSetter__('label', function(val) {\n  this.handleSetter('label', 'SetLabel', String, val);\n});\n\nMenuItem.prototype.__defineGetter__('icon', function() {\n  return this.handleGetter('shadowIcon');\n});\n\nMenuItem.prototype.__defineSetter__('icon', function(val) {\n  v8_util.getHiddenValue(this, 'option').shadowIcon = String(val);\n  var real_path = val == '' ? '' : nw.getAbsolutePath(val);\n  this.handleSetter('icon', 'SetIcon', String, real_path);","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/nwjs/nw.js/blob/e15da848e9e08e6e467532dae78995c6ad2f55ee/src/api/menuitem/menuitem.js#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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`."],"exampleFix":"// before\nitem.type = 'checkbox'; // throws\n\n// after\nmenu.remove(item);\nvar toggler = new nw.MenuItem({ type: 'checkbox', label: item.label, checked: true, click: item.click });\nmenu.append(toggler);","handlingStrategy":"validation","validationCode":"// type is set-once: never reassign it.\nfunction changeItemType(menu, item, newType) {\n  var opt = { type: newType, label: item.label, click: item.click };\n  if (item.icon) opt.icon = item.icon;\n  var next = new nw.MenuItem(opt);\n  var pos = menu.items.indexOf(item);\n  menu.remove(item);\n  menu.insert(next, pos);\n}","typeGuard":null,"tryCatchPattern":"try { item.type = newType; }\ncatch (e) {\n  if (e instanceof Error && /immutable/.test(e.message)) {\n    throw new Error('Cannot change item.type at runtime; rebuild the item.');\n  } throw e;\n}","preventionTips":["Treat `type` as read-only after construction.","Pick the correct type up front.","Avoid generic property-copy loops over menu items."],"tags":["nwjs","menuitem","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"}