nwjs/nw.js · error · TypeError

Invalid menu type: {option.type}

Error message

Invalid menu type: {option.type}

What it means

Menu's constructor accepts only two menu types: 'contextmenu' and 'menubar'. If option is not an object it defaults to {type:'contextmenu'}, but once an object is supplied its `type` must be one of those two literals or a TypeError is thrown. The invalid value is interpolated into the message.

Source

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

// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

var v8_util = process.binding('v8_util');
var EventEmitter = process.EventEmitter;


function Menu(option) {
  if (typeof option != 'object')
    option = { type: 'contextmenu' };

  if (option.type != 'contextmenu' && option.type != 'menubar')
    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");

View on GitHub (pinned to e15da848e9)

Solutions

  1. Use { type: 'contextmenu' } or { type: 'menubar' }.
  2. Pass no argument (or null) to get the default contextmenu, rather than an empty object.
  3. Check for typos and underscores; the values are single lowercase words.

Example fix

// before
new nw.Menu({ type: 'popup' }); // throws
new nw.Menu({}); // also throws (type undefined)

// after
new nw.Menu({ type: 'contextmenu' });
new nw.Menu(); // defaults to contextmenu
Defensive patterns

Strategy: validation

Validate before calling

var VALID = ['contextmenu', 'menubar'];
function buildMenu(option) {
  if (option && option.type && VALID.indexOf(option.type) === -1)
    throw new Error('Invalid menu type: ' + option.type);
  return new nw.Menu(option);
}

Type guard

function isMenuType(t) { return t === 'contextmenu' || t === 'menubar'; }

Try / catch

try { return new nw.Menu(option); }
catch (e) {
  if (e instanceof TypeError && /Invalid menu type/.test(e.message)) {
    return new nw.Menu({ type: 'contextmenu' }); // default fallback
  } throw e;
}

Prevention

When it happens

Trigger: Calling new nw.Menu({ type: 'popup' }), { type: 'bar' }, { type: 'menu' }, or any other string. Also { type: undefined } when the object exists but lacks a valid type.

Common situations: Developers coming from Electron (where Menu types are different) or guessing the type name ('popup', 'toolbar', 'tray'). Typos like 'context-menu' or 'menu_bar'. Passing an empty object when intending the default (an empty object does NOT default — its type is undefined and throws).

Related errors


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