nwjs/nw.js · error · TypeError
listener must be a function
Error message
listener must be a function
What it means
Thrown by NWWindow.prototype.once(event, listener, record) when typeof listener !== 'function'. The once method wraps the listener to auto-remove after first fire and forwards it to the background page's event recording; a non-function listener cannot be invoked or recorded, so it is rejected upfront.
Source
Thrown at src/resources/api_nw_window.js:178
privates(this).menu = null;
this.onClose = bindingUtil.createCustomEvent("nw.Window.onClose", true, false);
nwNatives.callInWindow(bgPage, "__nw_initwindow", currentRoutingID, this);
};
forEach(currentNWWindowInternal, function(key, value) {
if (!key.endsWith('Internal'))
NWWindow.prototype[key] = value;
});
NWWindow.prototype.onNewWinPolicy = bindingUtil.createCustomEvent('nw.Window.onNewWinPolicy', false, false);
NWWindow.prototype.onNavigation = bindingUtil.createCustomEvent('nw.Window.onNavigation', false, false);
NWWindow.prototype.LoadingStateChanged = bindingUtil.createCustomEvent('nw.Window.LoadingStateChanged', false, false);
NWWindow.prototype.onDocumentStart = bindingUtil.createCustomEvent('nw.Window.onDocumentStart', false, false);
NWWindow.prototype.onDocumentEnd = bindingUtil.createCustomEvent('nw.Window.onDocumentEnd', false, false);
NWWindow.prototype.onZoom = bindingUtil.createCustomEvent('nw.Window.onZoom', false, false);
NWWindow.prototype.once = function (event, listener, record) {
if (typeof listener !== 'function')
throw new TypeError('listener must be a function');
var fired = false;
var self = this;
if (typeof record === 'undefined') {
nwNatives.callInWindow(bgPage, "__nw_record_event", this, event, listener, true);
}
function g() {
nwNatives.callInWindow(bgPage, "__nw_removeOuterEventCB", self, event, listener);
self.removeListener(event, g);
if (!fired) {
fired = true;
listener.apply(self, arguments);
}
}
this.on(event, g, false);
return this;
};View on GitHub (pinned to e15da848e9)
Solutions
- Guard the call: if (cb) win.once('loaded', cb);.
- Pass a real function reference, not a name string.
- Resolve handler names from a registry before calling once().
Example fix
// before
win.once('loaded', maybeCallback); // maybeCallback may be undefined
// after
if (typeof maybeCallback === 'function') win.once('loaded', maybeCallback); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof listener !== 'function') {
throw new TypeError('win.once listener must be a function');
}
win.once(event, listener); Type guard
function isListenerFn(fn) { return typeof fn === 'function'; } Prevention
- Guard optional callbacks: if (cb) win.once(event, cb).
- Never pass handler name strings to once().
- Resolve handler names from a registry before subscribing.
When it happens
Trigger: win.once('loaded', null); win.once('close', undefined); win.once('focus', 'onFocus'); passing a config object instead of a callback.
Common situations: Optional callback patterns where the caller passes a possibly-undefined value without guarding; refactoring from on() to once() and forgetting to ensure the callback; JSON-loaded handler names.
Related errors
- Only menu of type "menubar" can be used as this.window menu
- Invalid menu type: {option.type}
- Invalid option.
- Invalid MenuItem type: {option.type}
- A normal MenuItem must have a label
AI-assisted analysis of nwjs/nw.js@e15da848e9 (2026-08-13).
Data as JSON: /api/errors/26512546bc56b897.
Report an issue: GitHub.