{"record":{"id":"eb45cbb00f73f378","repo":"nwjs/nw.js","slug":"listener-must-be-a-function","errorCode":null,"errorMessage":"listener must be a function","messagePattern":"listener must be a function","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/resources/api_nw_app.js","lineNumber":78,"sourceCode":"  });\n  apiFunctions.setHandleRequest('getProxyForURL', function() {\n    return nwNatives.getProxyForURL.apply(this, arguments);\n  });\n  apiFunctions.setHandleRequest('addOriginAccessWhitelistEntry', function() {\n    nwNatives.addOriginAccessWhitelistEntry.apply(this, arguments);\n  });\n  apiFunctions.setHandleRequest('removeOriginAccessWhitelistEntry', function() {\n    nwNatives.removeOriginAccessWhitelistEntry.apply(this, arguments);\n  });\n\n  // Event methods defined directly on compiledApi to bypass the API bridge's\n  // argument parsing which wraps function callbacks in native bindings that\n  // become inert after the first invocation.\n  var compiledApi = bindingsAPI.compiledApi;\n\n  compiledApi.once = function(event, listener) {\n    if (typeof listener !== 'function')\n      throw new TypeError('listener must be a function');\n    var fired = false;\n    var self = this;\n\n    function g() {\n      self.removeListener(event, g);\n      if (!fired) {\n        fired = true;\n        listener.apply(self, arguments);\n      }\n    }\n    this.on(event, g);\n    return this;\n  };\n\n  compiledApi.on = function(event, callback) {\n      if (eventsMap.hasOwnProperty(event)) {\n        compiledApi[eventsMap[event]].addListener(callback);\n      }","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/nwjs/nw.js/blob/e15da848e9e08e6e467532dae78995c6ad2f55ee/src/resources/api_nw_app.js#L60-L96","documentation":"Thrown by nw.App.once when the listener argument is not a function. `once` is a custom EventEmitter-style method that registers a one-shot listener on the compiled API object, bypassing the API bridge, so it performs its own typeof check before registering.","triggerScenarios":"Calling `nw.App.once('argv', undefined)`, `nw.App.once('open', 'handler')`, or passing a value from an optional config that defaulted to null.","commonSituations":"Passing a handler looked up by name that did not resolve; copy-paste from an API that accepts a string event name as the listener.","solutions":["Pass a function: `nw.App.once('open', (path) => {})`.","Guard the call: `if (typeof cb === 'function') nw.App.once(ev, cb);`."],"exampleFix":"// before\nnw.App.once('open', handlers.onOpen);\n// after\nif (typeof handlers.onOpen === 'function') nw.App.once('open', handlers.onOpen);","handlingStrategy":"type-guard","validationCode":"if (typeof listener !== 'function') throw new TypeError('listener must be a function');","typeGuard":"function isListener(v) { return typeof v === 'function'; }","tryCatchPattern":"try { nw.App.once(ev, cb); } catch (e) { if (/listener/.test(e.message)) console.warn('Skipped non-function listener'); else throw e; }","preventionTips":["Resolve handler references before subscribing.","Use a thin wrapper that checks typeof before calling once."],"tags":["app","events","type-check","nwjs"],"backgroundTag":null,"analyzedSha":"e15da848e9e08e6e467532dae78995c6ad2f55ee","analyzedAt":"2026-08-13T04:15:35.452Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}