{"record":{"id":"fa524c4a9f1d9f48","repo":"nwjs/nw.js","slug":"nw-callstaticmethodsync-screen-addscreenchangecal","errorCode":null,"errorMessage":"nw.callStaticMethodSync(Screen, AddScreenChangeCallback) fails","messagePattern":"nw\\.callStaticMethodSync\\(Screen, AddScreenChangeCallback\\) fails","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/api/screen/screen.js","lineNumber":46,"sourceCode":"\n// Override the addListener method.\nScreen.prototype.on = Screen.prototype.addListener = function(ev, callback) {\n  if ( ev != \"displayBoundsChanged\" && ev != \"displayAdded\" && ev != \"displayRemoved\" && ev != \"chooseDesktopMedia\")\n    throw new TypeError('only following event can be listened: displayBoundsChanged, displayAdded, displayRemoved');\n  \n  var onRemoveListener = function (type, listener) {\n    if (this._numListener > 0) {\n      this._numListener--;\n      if (this._numListener == 0) {\n        process.EventEmitter.prototype.removeListener.apply(this, [\"removeListener\", onRemoveListener]);\n        nw.callStaticMethodSync('Screen', 'RemoveScreenChangeCallback', [ this.id ]);\n      }\n    }\n  };\n\n  if(this._numListener == 0) {\n    if (nw.callStaticMethodSync('Screen', 'AddScreenChangeCallback', [ this.id ])[0] == false ) {\n      throw new Error('nw.callStaticMethodSync(Screen, AddScreenChangeCallback) fails');\n      return;\n    }\n    process.EventEmitter.prototype.addListener.apply(this, [\"removeListener\", onRemoveListener]);\n  }\n  \n  // Call parent.\n  process.EventEmitter.prototype.addListener.apply(this, arguments);\n  this._numListener++;\n}\n\n// Route events.\nScreen.prototype.handleEvent = function(ev) {\n  if (ev != \"chooseDesktopMedia\")\n    arguments[1] = JSON.parse(arguments[1]);\n  // Call parent.\n  this.emit.apply(this, arguments);\n}\n","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/nwjs/nw.js/blob/e15da848e9e08e6e467532dae78995c6ad2f55ee/src/api/screen/screen.js#L28-L64","documentation":"On the first listener, Screen.on calls the native AddScreenChangeCallback and expects a truthy result. If the native side returns false (callback registration failed in the C++ layer), a plain Error is thrown. Unlike the validation errors, this reflects an environment/platform failure rather than bad arguments. The `return` after the throw is dead code.","triggerScenarios":"Calling nw.Screen.on('displayBoundsChanged', fn) when the native screen-observer infrastructure failed to initialize — e.g., during very early startup, headless/CI environments without a display, or a platform where the screen-change observer is unsupported.","commonSituations":"Running nw.js in a headless/automated environment (CI, Docker without X11). Platform-specific observer failures (some Linux WMs, certain virtual displays). Resource exhaustion during startup.","solutions":["Run in an environment with a real display (or Xvfb on Linux CI).","Defer Screen listener registration until after the window/main module has loaded.","Wrap the call in try/catch and degrade gracefully (log and skip the feature)."],"exampleFix":"// before\nnw.Screen.on('displayAdded', syncDisplays); // may throw in headless CI\n\n// after\ntry {\n  nw.Screen.on('displayAdded', syncDisplays);\n} catch (e) {\n  if (/AddScreenChangeCallback/.test(e.message)) {\n    console.warn('Screen observer unavailable; multi-monitor features disabled.');\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Cannot validate a native failure up front; ensure a display exists instead.\nfunction hasDisplay() {\n  try { return nw.Screen && !!nw.Screen.screens; } catch (e) { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  nw.Screen.on('displayAdded', fn);\n} catch (e) {\n  if (e instanceof Error && /AddScreenChangeCallback/.test(e.message)) {\n    console.warn('Screen observer unavailable; skipping multi-monitor features.');\n  } else { throw e; }\n}","preventionTips":["Run nw.js with a real display (Xvfb on Linux CI).","Register screen listeners after the main window loads.","Gracefully degrade features that depend on screen-change events."],"tags":["nwjs","screen","native","environment","headless"],"backgroundTag":null,"analyzedSha":"e15da848e9e08e6e467532dae78995c6ad2f55ee","analyzedAt":"2026-08-13T04:15:35.452Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}