Skip to content

screen.grab() doesn't work on macOS Tahoe #625

@domdomegg

Description

@domdomegg

Version

nut-js 4.2.6, libnut-darwin 2.7.5

Short overview

screen.grab() fails with "Failed to capture screen" on macOS 26 (Tahoe). I think this may be related to nut-tree/libnut-core#187, and be because Apple has now fully removed CGDisplayCreateImageForRect from the CoreGraphics dylib in macOS 26, so the call from screengrab.m there fails at runtime.

Issue occurs on

  • Virtual machine
  • Docker container
  • Dev/Host system

node version: v25.6.1

OS type and version: macOS 26.1 (Tahoe), build 25B78, arm64

Detailed error description

screengrab.m calls CGDisplayCreateImageForRect (line 22). This API was deprecated in macOS 15 (Sequoia) in favour of ScreenCaptureKit, but the symbol still existed at runtime so everything kept working. In macOS 26 (Tahoe), Apple fully removed it:

$ nm -g /System/Library/Frameworks/CoreGraphics.framework/CoreGraphics | grep CGDisplayCreateImageForRect
(no output — symbol gone)

Similarly, CGWindowListCreateImage (used elsewhere) is also gone:

$ swift -e 'import CoreGraphics; let _ = CGWindowListCreateImage(.infinite, .optionOnScreenOnly, kCGNullWindowID, .bestResolution)'
error: 'CGWindowListCreateImage' is unavailable in macOS: Please use ScreenCaptureKit instead.
note: 'CGWindowListCreateImage' was obsoleted in macOS 15.0

Other screen capture methods still work — the screencapture CLI produces valid screenshots, and accessibility/mouse APIs (getMousePos, moveMouse, etc.) are unaffected. Only captureScreen fails.

Full code sample to reproduce

const { screen } = require("@nut-tree/nut-js");

screen.grab().then((img) => {
  console.log("Success:", img.width, "x", img.height);
}).catch((err) => {
  console.error("Error:", err.message);
});

Output:

Error: Error: Failed to capture screen
    at libnut.<computed> (permissionCheck.js:82:58)
    at libnut.<computed> [as captureScreen] (permissionCheck.js:87:60)
    at module.exports.screen.capture (index.js:40:20)
    ...

Note: getAuthStatus("screen") returns "authorized" — permissions are granted, the underlying API just no longer exists.

Additional content

The fix likely needs to happen in libnut-core/src/macos/screengrab.m, by replacing CGDisplayCreateImageForRect with ScreenCaptureKit (SCScreenshotManager.captureImage) on macOS 15+

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions