nwjs/nw.js · error · TypeError
'menu' must be a valid Menu
Error message
'menu' must be a valid Menu
What it means
Thrown by the nw.Tray constructor when 'menu' is present but the value's constructor name is not 'Menu'. nw validates the menu via v8_util.getConstructorName, so a plain object or any non-nw.Menu instance is rejected even if it looks menu-like.
Source
Thrown at src/api/tray/tray.js:63
if (option.hasOwnProperty('iconsAreTemplates'))
option.iconsAreTemplates = Boolean(option.iconsAreTemplates);
else
option.iconsAreTemplates = true;
if (option.hasOwnProperty('tooltip'))
option.tooltip = String(option.tooltip);
if (option.hasOwnProperty('click')) {
if (typeof option.click != 'function') {
throw new TypeError("'click' must be a valid Function");
} else {
this.click = option.click;
}
}
if (option.hasOwnProperty('menu')) {
if (v8_util.getConstructorName(option.menu) != 'Menu')
throw new TypeError("'menu' must be a valid Menu");
// Transfer only object id
v8_util.setHiddenValue(this, 'menu', option.menu);
option.menu = option.menu.id;
}
v8_util.setHiddenValue(this, 'option', option);
nw.allocateObject(this, option);
// All properties must be set after initialization.
if (!option.hasOwnProperty('icon'))
option.shadowIcon = '';
if (!option.hasOwnProperty('alticon'))
option.shadowAlticon = '';
if (!option.hasOwnProperty('tooltip'))
option.tooltip = '';
}
require('util').inherits(Tray, exports.Base);View on GitHub (pinned to e15da848e9)
Solutions
- Build the menu with `new nw.Menu({ type: 'contextmenu', items: [...] })` before passing it.
- Ensure the same Menu class (nw.Menu) is used, not a custom subclass with a different constructor name.
Example fix
// before
new nw.Tray({ menu: { items: [{ label: 'x' }] } });
// after
const menu = new nw.Menu();
menu.append(new nw.MenuItem({ label: 'x' }));
new nw.Tray({ menu }); Defensive patterns
Strategy: type-guard
Validate before calling
if (option.hasOwnProperty('menu') && !(option.menu instanceof nw.Menu)) {
throw new Error('option.menu must be a nw.Menu instance');
} Type guard
function isMenu(v) { return v && v.constructor && v.constructor.name === 'Menu'; } Try / catch
try { new nw.Tray(opt); } catch (e) { if (/menu/.test(e.message)) { opt.menu = new nw.Menu(); new nw.Tray(opt); } else throw e; } Prevention
- Always construct menus with new nw.Menu().
- Do not pass deserialized JSON objects as menus.
When it happens
Trigger: Calling `new nw.Tray({ menu: { items: [] } })` or passing a JSON-deserialized object as the menu.
Common situations: Passing a submenu built with a different framework; forgetting to wrap items in `new nw.Menu({ ... })`.
Related errors
- Invalid option
- 'click' must be a valid Function
- 'menu' property requries a valid Menu
- Invalid menu type: {option.type}
- 'active' must be a valid function.
AI-assisted analysis of nwjs/nw.js@e15da848e9 (2026-08-13).
Data as JSON: /api/errors/011b186ade9bd257.
Report an issue: GitHub.