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 when the listener argument is not a function. `once` is a custom one-shot wrapper around on()/removeListener() defined directly on NWWindow, so it validates the listener itself before registering.
Source
Thrown at src/resources/api_nw_newwin.js:134
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.onClose = bindingUtil.createCustomEvent("nw.Window.onClose", true, false);
NWWindow.prototype.onMinimized = bindingUtil.createCustomEvent("nw.Window.onMinimized", false, false);
NWWindow.prototype.onMaximized = bindingUtil.createCustomEvent("nw.Window.onMaximized", false, false);
NWWindow.prototype.onFullscreen = bindingUtil.createCustomEvent("nw.Window.onFullscreen", false, false);
NWWindow.prototype.onResized = bindingUtil.createCustomEvent("nw.Window.onResized", false, false);
NWWindow.prototype.onRestore = bindingUtil.createCustomEvent("nw.Window.onRestore", false, false);
NWWindow.prototype.close = function (force) {
//console.log(`---> NWWindow.close: ${force} ${this.cWindow.id}`);
currentNWWindowInternal.close(force, this.cWindow.id);
}
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;
function g() {
self.removeListener(event, g);
if (!fired) {
fired = true;
listener.apply(self, arguments);
}
}
this.on(event, g, false);
return this;
};
NWWindow.prototype.on = function (event, callback, record) {
var self = this;
// Wrap callback to bind to `self`.View on GitHub (pinned to e15da848e9)
Solutions
- Pass a function: `win.once('closed', () => {})`.
- Guard: `if (typeof cb === 'function') win.once(ev, cb);`.
- Prefer win.on() if you actually want repeated notifications.
Example fix
// before
win.once('closed', handlers.onClose);
// after
if (typeof handlers.onClose === 'function') win.once('closed', handlers.onClose); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof listener !== 'function') throw new TypeError('listener must be a function'); Type guard
function isListener(v) { return typeof v === 'function'; } Try / catch
try { win.once(ev, cb); } catch (e) { if (/listener/.test(e.message)) console.warn('non-function listener skipped'); else throw e; } Prevention
- Resolve handler references before subscribing.
- Use win.on() for repeated notifications.
When it happens
Trigger: Calling `win.once('closed', undefined)`, `win.once('maximized', 'handler')`, or passing a null reference.
Common situations: Handler looked up dynamically resolved to undefined; passing a config value instead of a function.
Related errors
- listener must be a function
- only following event can be listened: displayBoundsChanged,
- 'active' must be a valid function.
- 'failed' must be a valid function.
- Invalid option
AI-assisted analysis of nwjs/nw.js@e15da848e9 (2026-08-13).
Data as JSON: /api/errors/08d1e40adc14a0c9.
Report an issue: GitHub.