nwjs/nw.js · error · TypeError

Menu.append() requires a valid MenuItem

Error message

Menu.append() requires a valid MenuItem

What it means

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.

Source

Thrown at src/api/menu/menu.js:48

    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 ]);
  this.items.splice(pos_hint, 1);
}

Menu.prototype.removeAt = function(i) {
  nw.callObjectMethod(this, 'Remove', [ this.items[i].id, i ]);

View on GitHub (pinned to e15da848e9)

Solutions

  1. Wrap each entry with `new nw.MenuItem({ label: 'x', click: fn })` before appending.
  2. Use a helper that always constructs MenuItem instances.
  3. If sharing across frames, construct the items in the same context that owns the Menu.

Example fix

// before
menu.append({ label: 'Open', click: onOpen }); // throws

// after
menu.append(new nw.MenuItem({ label: 'Open', click: onOpen }));
Defensive patterns

Strategy: type-guard

Validate before calling

function appendItem(menu, item) {
  if (!(item instanceof nw.MenuItem))
    item = new nw.MenuItem(item);
  menu.append(item);
}

Type guard

function isMenuItem(v) {
  return v instanceof nw.MenuItem ||
    (v && typeof v === 'object' && v.constructor && v.constructor.name === 'MenuItem');
}

Try / catch

try { menu.append(item); }
catch (e) {
  if (e instanceof TypeError && /valid MenuItem/.test(e.message)) {
    menu.append(new nw.MenuItem(item));
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of nwjs/nw.js@e15da848e9 (2026-08-13). Data as JSON: /api/errors/5ae1fcf199ba5823. Report an issue: GitHub.