nwjs/nw.js · error · TypeError

only following event can be listened: displayBoundsChanged,

Error message

only following event can be listened: displayBoundsChanged, displayAdded, displayRemoved

What it means

Screen overrides `on`/`addListener` and rejects any event name outside its whitelist. Note a discrepancy: the condition ALSO accepts 'chooseDesktopMedia', but the error message lists only the three display events — so the message under-reports the allowed set. Any other event name throws a TypeError.

Source

Thrown at src/api/screen/screen.js:32

// 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 screenInstance = null;

function Screen() {
  nw.allocateObject(this, {});
  this._numListener = 0;
}
require('util').inherits(Screen, exports.Base);

// Override the addListener method.
Screen.prototype.on = Screen.prototype.addListener = function(ev, callback) {
  if ( ev != "displayBoundsChanged" && ev != "displayAdded" && ev != "displayRemoved" && ev != "chooseDesktopMedia")
    throw new TypeError('only following event can be listened: displayBoundsChanged, displayAdded, displayRemoved');
  
  var onRemoveListener = function (type, listener) {
    if (this._numListener > 0) {
      this._numListener--;
      if (this._numListener == 0) {
        process.EventEmitter.prototype.removeListener.apply(this, ["removeListener", onRemoveListener]);
        nw.callStaticMethodSync('Screen', 'RemoveScreenChangeCallback', [ this.id ]);
      }
    }
  };

  if(this._numListener == 0) {
    if (nw.callStaticMethodSync('Screen', 'AddScreenChangeCallback', [ this.id ])[0] == false ) {
      throw new Error('nw.callStaticMethodSync(Screen, AddScreenChangeCallback) fails');
      return;
    }
    process.EventEmitter.prototype.addListener.apply(this, ["removeListener", onRemoveListener]);
  }

View on GitHub (pinned to e15da848e9)

Solutions

  1. Use one of the supported events: 'displayBoundsChanged', 'displayAdded', 'displayRemoved' (and 'chooseDesktopMedia' for the dedicated API).
  2. Copy event names exactly, including camelCase and the trailing 'Changed'/'Added'/'Removed'.
  3. For desktop-media capture, prefer nw.Screen.chooseDesktopMedia(...) which wires the callback internally.

Example fix

// before
nw.Screen.on('displays-changed', fn); // throws

// after
nw.Screen.on('displayBoundsChanged', fn);
nw.Screen.on('displayAdded', fn);
nw.Screen.on('displayRemoved', fn);
Defensive patterns

Strategy: validation

Validate before calling

var SCREEN_EVENTS = ['displayBoundsChanged', 'displayAdded', 'displayRemoved', 'chooseDesktopMedia'];
function onScreen(ev, cb) {
  if (SCREEN_EVENTS.indexOf(ev) === -1)
    throw new TypeError('Unsupported screen event: ' + ev);
  nw.Screen.on(ev, cb);
}

Type guard

function isScreenEvent(ev) {
  return ['displayBoundsChanged','displayAdded','displayRemoved','chooseDesktopMedia'].indexOf(ev) !== -1;
}

Try / catch

try { nw.Screen.on(ev, cb); }
catch (e) {
  if (e instanceof TypeError && /only following event/.test(e.message)) {
    console.warn('Ignoring unsupported screen event:', ev);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling nw.Screen.on('resize', fn), .on('change', fn), or any custom event. Even a typo like 'displayBoundChanged' (missing 's') throws.

Common situations: Assuming Screen is a general EventEmitter and listening for arbitrary names. Migrating from Electron's `screen.on('display-metrics-changed')`. Typos in the long event names.

Related errors


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