{"record":{"id":"5ae1fcf199ba5823","repo":"nwjs/nw.js","slug":"menu-append-requires-a-valid-menuitem","errorCode":null,"errorMessage":"Menu.append() requires a valid MenuItem","messagePattern":"Menu\\.append\\(\\) requires a valid MenuItem","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/api/menu/menu.js","lineNumber":48,"sourceCode":"    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 ]);\n  this.items.splice(pos_hint, 1);\n}\n\nMenu.prototype.removeAt = function(i) {\n  nw.callObjectMethod(this, 'Remove', [ this.items[i].id, i ]);","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/nwjs/nw.js/blob/e15da848e9e08e6e467532dae78995c6ad2f55ee/src/api/menu/menu.js#L30-L66","documentation":"Menu.prototype.append checks that the argument's constructor name is exactly 'MenuItem' before pushing it onto the items array and calling the native Append. Anything else — a plain object, a string, an element from another frame — is rejected with a TypeError to protect the native call that dereferences menu_item.id.","triggerScenarios":"Calling menu.append({label:'x'}), menu.append('label'), or menu.append(someTrayItem). Also a MenuItem created in another context whose constructor name does not match.","commonSituations":"Developers build menu entries as plain option objects and forget to wrap them with `new nw.MenuItem(...)`. Mixing up MenuItem with Tray or other API objects. Cross-frame menu construction.","solutions":["Wrap each entry with `new nw.MenuItem({ label: 'x', click: fn })` before appending.","Use a helper that always constructs MenuItem instances.","If sharing across frames, construct the items in the same context that owns the Menu."],"exampleFix":"// before\nmenu.append({ label: 'Open', click: onOpen }); // throws\n\n// after\nmenu.append(new nw.MenuItem({ label: 'Open', click: onOpen }));","handlingStrategy":"type-guard","validationCode":"function appendItem(menu, item) {\n  if (!(item instanceof nw.MenuItem))\n    item = new nw.MenuItem(item);\n  menu.append(item);\n}","typeGuard":"function isMenuItem(v) {\n  return v instanceof nw.MenuItem ||\n    (v && typeof v === 'object' && v.constructor && v.constructor.name === 'MenuItem');\n}","tryCatchPattern":"try { menu.append(item); }\ncatch (e) {\n  if (e instanceof TypeError && /valid MenuItem/.test(e.message)) {\n    menu.append(new nw.MenuItem(item));\n  } else throw e;\n}","preventionTips":["Always wrap entries with new nw.MenuItem(...).","Use a helper that coerces plain objects to MenuItem.","Construct items in the same context as the Menu."],"tags":["nwjs","menu","menuitem","type-validation"],"backgroundTag":null,"analyzedSha":"e15da848e9e08e6e467532dae78995c6ad2f55ee","analyzedAt":"2026-08-13T04:15:35.452Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}