nwjs/nw.js · error · TypeError

'submenu' property requries a valid Menu

Error message

'submenu' property requries a valid Menu

What it means

The runtime `submenu` setter (distinct from the constructor-time check) throws a TypeError if the value's constructor name is not 'Menu'. On success it stashes the Menu in a hidden value and calls the native SetSubmenu with the Menu's id. The message contains a typo ("requries").

Source

Thrown at src/api/menuitem/menuitem.js:184

  this.handleSetter('checked', 'SetChecked', Boolean, val);
});

MenuItem.prototype.__defineGetter__('enabled', function() {
  return this.handleGetter('enabled');
});

MenuItem.prototype.__defineSetter__('enabled', function(val) {
  this.handleSetter('enabled', 'SetEnabled', Boolean, val);
});

MenuItem.prototype.__defineGetter__('submenu', function() {
  return v8_util.getHiddenValue(this, 'submenu');
});

MenuItem.prototype.__defineSetter__('submenu', function(val) {
  if (v8_util.getConstructorName(val) != 'Menu')
    throw new TypeError("'submenu' property requries a valid Menu");

  v8_util.setHiddenValue(this, 'submenu', val);
  nw.callObjectMethod(this, 'SetSubmenu', [ val.id ]);
});

MenuItem.prototype.handleEvent = function(ev) {
  if (ev == 'click') {
    // Automatically flag the 'checked' property.
    if (this.type == 'checkbox') {
      var option = v8_util.getHiddenValue(this, 'option');
      option.checked = !option.checked;
    }

    // Emit click handler
    if (typeof this.click == 'function')
      this.click();
  }

View on GitHub (pinned to e15da848e9)

Solutions

  1. Build a nw.Menu instance and assign that: `item.submenu = new nw.Menu();`.
  2. To clear, assign an empty nw.Menu rather than null or [].
  3. Rebuild child items into the new Menu before attaching.

Example fix

// before
item.submenu = [{ label: 'Recent' }]; // throws
item.submenu = null;                   // throws

// after
var recent = new nw.Menu();
recent.append(new nw.MenuItem({ label: 'Recent' }));
item.submenu = recent;
Defensive patterns

Strategy: type-guard

Validate before calling

function setSubmenu(item, submenu) {
  if (submenu && !(submenu instanceof nw.Menu))
    throw new TypeError('submenu must be a nw.Menu');
  item.submenu = submenu;
}

Type guard

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

Try / catch

try { item.submenu = val; }
catch (e) {
  if (e instanceof TypeError && /submenu.*valid Menu/.test(e.message)) {
    var m = new nw.Menu();
    item.submenu = m; // assign a real (possibly empty) Menu
  } else throw e;
}

Prevention

When it happens

Trigger: Assigning `item.submenu = []`, `item.submenu = otherItem`, or `item.submenu = null` at runtime. Passing a Menu from a different JS realm.

Common situations: Dynamically swapping submenus at runtime (e.g., rebuilding a recent-files list). Developers assign an array of items expecting auto-conversion. Clearing a submenu by assigning null.

Related errors


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