nwjs/nw.js · error · TypeError
'submenu' must be a valid Menu
Error message
'submenu' must be a valid Menu
What it means
When the `submenu` property is present on a normal/checkbox MenuItem option, the constructor verifies its constructor name equals 'Menu'. Anything else (a plain array, a string, a MenuItem, a Menu from another realm) throws a TypeError. On success only the Menu's id is forwarded to the native side and the real Menu is stashed in a hidden value.
Source
Thrown at src/api/menuitem/menuitem.js:62
if (option.hasOwnProperty('icon')) {
option.shadowIcon = String(option.icon);
option.icon = nw.getAbsolutePath(option.icon);
}
if (option.hasOwnProperty('iconIsTemplate'))
option.iconIsTemplate = Boolean(option.iconIsTemplate);
else
option.iconIsTemplate = true;
if (option.hasOwnProperty('tooltip'))
option.tooltip = String(option.tooltip);
if (option.hasOwnProperty('enabled'))
option.enabled = Boolean(option.enabled);
if (option.hasOwnProperty('submenu')) {
if (v8_util.getConstructorName(option.submenu) != 'Menu')
throw new TypeError("'submenu' must be a valid Menu");
// Transfer only object id
v8_util.setHiddenValue(this, 'submenu', option.submenu);
option.submenu = option.submenu.id;
}
if (option.hasOwnProperty('click')) {
if (typeof option.click != 'function')
throw new TypeError("'click' must be a valid Function");
else
this.click = option.click;
}
} else if (option.type == 'separator') {
option = {
type: 'separator'
};
}
View on GitHub (pinned to e15da848e9)
Solutions
- Build the submenu as a nw.Menu and pass that instance: `new nw.MenuItem({ label:'x', submenu: subMenu })`.
- Construct child items into the submenu Menu first, then attach the submenu.
- Keep the Menu in the same JS context as the MenuItem.
Example fix
// before
new nw.MenuItem({ label: 'Edit', submenu: [{label:'Cut'}] }); // throws
// after
var sub = new nw.Menu();
sub.append(new nw.MenuItem({ label: 'Cut', click: onCut }));
new nw.MenuItem({ label: 'Edit', submenu: sub }); Defensive patterns
Strategy: type-guard
Validate before calling
function withSubmenu(opt, submenu) {
if (submenu && !(submenu instanceof nw.Menu))
throw new TypeError('submenu must be a nw.Menu');
opt.submenu = submenu;
return new nw.MenuItem(opt);
} Type guard
function isMenu(v) {
return v instanceof nw.Menu ||
(v && typeof v === 'object' && v.constructor && v.constructor.name === 'Menu');
} Try / catch
try { return new nw.MenuItem(opt); }
catch (e) {
if (e instanceof TypeError && /submenu.*valid Menu/.test(e.message)) {
var m = new nw.Menu();
opt.submenu.forEach(function (i) { m.append(new nw.MenuItem(i)); });
opt.submenu = m;
return new nw.MenuItem(opt);
} throw e;
} Prevention
- Always build the submenu as a nw.Menu instance.
- Do not pass arrays of plain option objects as submenu.
- Construct the submenu in the same JS context as the parent item.
When it happens
Trigger: Calling new nw.MenuItem({ label:'x', submenu: [] }), { label:'x', submenu: 'file' }, or passing a MenuItem as the submenu. Also a Menu built in a different context.
Common situations: Developers pass an array of items expecting auto-construction (common in other UI libs). Confusing submenu (a Menu) with the items list. Cross-frame menu sharing.
Related errors
- Menu.append() requires a valid MenuItem
- 'submenu' property requries a valid Menu
- 'click' must be a valid Function
- Invaild parameter, need Shortcut object.
- Type of '{type}' is not supported
AI-assisted analysis of nwjs/nw.js@e15da848e9 (2026-08-13).
Data as JSON: /api/errors/7c0bd1d977f32e76.
Report an issue: GitHub.