Skip to content

[Bug]: macOS SnapShots capture a helper window instead of the real one, giving tiny images for Chrome and Electron apps #16077

Closed

Description

@rithwikshetty

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

  1. On macOS, enable SnapShots with Screen Recording and Accessibility granted.
  2. Bring forward an app that keeps thin helper windows on the normal window layer in front of its main window. Chrome did this on my machine (window list below), and so do Electron apps.
  3. Take a SnapShot with the shortcut.

Expected behavior

The SnapShot shows the window I was looking at, at full size.

Actual behavior

The SnapShot is a tiny, unreadable image. Taking a SnapShot of an Electron app's main window from T3 Code Nightly gave a 51×32 PNG of the whole window. The attachment metadata named the right app and window title, but the image was too small to read. A screenshot is in the comments.

Cause, from reading the code:

  • macActiveWindow in apps/desktop/src/snapShot/ActiveWindow.ts runs a JXA script. The script returns the frontmost app's first on-screen window with kCGWindowLayer === 0, in front-to-back order.

  • Some apps list untitled helper windows first. This is Chrome's on-screen layer-0 list from my machine, front to back:

    id    title                       x  y    width  height
    75    ""                          0  39   1800   41
    74    ""                          0  80   1800   81
    1691  ""                          0  39   1800   158
    71    "(10) … - YouTube"          0  161  1800   1008   <- the real window
    

    The lookup returns window 75.

  • captureMacWindowSnapshot captures screencapture -l <id> and then scales the image down to fit snapShotThumbnailSize(active), which comes from the chosen window's bounds. When the chosen window is a strip or a tiny helper, the result is a strip or a thumbnail.

How this was established: I hit it in a downstream fork that shares this code path. There, ActiveWindow.ts and MacSnapShot.ts are identical to main apart from comments. The 51×32 capture above came from stock T3 Code Nightly. The Chrome window list came from running the same CoreGraphics query directly. I did not take a T3 SnapShot of Chrome in that state, and I did not identify which window gave the 51×32 bounds in the Electron case. Chrome does not always order its windows this way: #10896 shows a Chrome capture that picked the right window.

Impact

Major degradation or frequent failure

Version or commit

T3 Code Nightly 0.0.46-nightly.20261005.2667. Code read at main @ 1a3f7ad.

Environment

macOS 27.0.1, Apple Silicon

Logs or stack traces

No response

Workaround

None for the user. In the fork, the JXA script now returns every on-screen layer-0 window of the frontmost app, with its title, bounds and kCGWindowAlpha. A small TypeScript function picks one:

const MIN_MAC_WINDOW_SIDE = 100;

export function pickMacActiveWindow(windows) {
  const visible = windows.filter((window) => window.alpha > 0);
  const titled = visible.find(
    (window) =>
      window.title.trim() !== "" &&
      window.bounds.width >= MIN_MAC_WINDOW_SIDE &&
      window.bounds.height >= MIN_MAC_WINDOW_SIDE,
  );
  if (titled) return titled;
  // No titled window, for example without Screen Recording: take the largest.
  return visible.reduce(
    (largest, window) =>
      !largest ||
      window.bounds.width * window.bounds.height > largest.bounds.width * largest.bounds.height
        ? window
        : largest,
    undefined,
  );
}

With the whole list in the output, maxBuffer also needs raising from 64 KiB. I used 1 MiB. Moving the choice into TypeScript also lets it be unit-tested without osascript.

Related: #12103 is a different failure in the same lookup (frontmostApplication reports PID -1 for Device Hub).

Investigated and drafted with Claude Code (Claude Opus 5.5).

Activity

  1. rithwikshetty commented on Oct 5, 2026

    @rithwikshetty
    Author

    This is how it looks when I snapshot t3code

    Image
  2. juliusmarminge commented on Oct 5, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks for the detailed write-up and the Chrome window list, @rithwikshetty. The ordering evidence and the pointer into macActiveWindow made this straightforward to follow.

    What I found

    • On main at 1a3f7ad508, macActiveWindow returns the frontmost app's first on-screen layer-0 window, front to back (apps/desktop/src/snapShot/ActiveWindow.ts). captureMacWindowSnapshot then runs screencapture -l on that id and scales the PNG down to snapShotThumbnailSize(active), which is the chosen window's bounds (capped at 2560×1600).
    • When a helper is listed ahead of the real window, that helper becomes the capture. If its bounds are about 51×32, the saved PNG is 51×32 even when screencapture returned the whole window. That matches the composer image you attached.
    • One caveat on the T3 Code capture: when the chosen window's title is empty, the attachment stores the owner name as the title. So app name and window title both reading "T3 Code" does not by itself prove the selected window was the main one.
    • Your Chrome list is direct evidence of the ordering bug. Those three untitled windows sit in front of the YouTube window, so this lookup returns window 75 (1800×41), not window 71. That capture would be a strip, not 51×32, and this report did not include a SnapShot taken in that Chrome state. A CoreGraphics dump from the Electron capture that produced the 51×32 file would identify that window.
    • Open PR fix(desktop): skip auxiliary macOS snapshot windows #12978 targets the same bug and is not merged. Its filter only skips untitled strips that share the origin of the app's largest window. These Chrome windows do not: the content window is at y=161 and the strips are at y=39 and y=80, so that PR would still select window 75. It also intentionally keeps offset untitled strips, untitled dialogs, and small titled windows.
    • The 100px titled-window picker in your report would select the YouTube window, and it would also drop those dialogs and small windows. Returning every layer-0 window from the script also needs a larger maxBuffer than the current 64 KiB, but that buffer is not what failed here. MacSettingsWindow already ignores windows under 500×350, but only while looking for System Settings' one content window.
    • SnapShot shortcut cannot capture Xcode Device Hub on macOS 27 #12103 is a different failure in the same lookup (Device Hub's PID is -1). [Bug]: Chrome SnapShots omit accessibility data on macOS when window titles differ #10896 is the accessibility-title mismatch; that report's Chrome capture got the right window.

    Likely fix area

    • Change the macOS SnapShot window picker so it does not take the first layer-0 window when that window is an untitled strip or tiny helper. Options include returning the full on-screen layer-0 list from JXA and choosing in TypeScript (as in your pickMacActiveWindow sketch), preferring a titled window above a minimum size, or falling back to the largest visible window.
    • If the full list is returned, raise maxBuffer above 64 KiB so large window lists do not truncate.
    • Keep the fix(desktop): skip auxiliary macOS snapshot windows #12978 approach in mind, but its current filter alone does not cover the Chrome ordering in this report.

    A maintainer will decide on the fix direction.

  3. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 5, 2026
  4. AlexHoff97 commented on Oct 7, 2026

    @AlexHoff97

    I have this exact issue as well.

  5. pnachtlberger commented on Oct 17, 2026

    @pnachtlberger

    Another data point, still present in T3 Code Nightly 0.1.1-nightly.20261016.3203 (macOS 26.5.2). It happens reliably when Chrome is in native fullscreen; the same window captures fine when not fullscreen. The SnapShot is a 36×20 image of a window titled "Window" (AX: WindowSharingSessionButton).

    Chrome's on-screen layer-0 windows in fullscreen, front to back:

    id    title     x,y     size       alpha
    5847  "Window"  10,-26  66x20      0
    594   ""        0,0     1920x81    1
    679   ""        0,0     1920x149   1
    591   "<tab>"   0,81    1920x999   1   <- the real window
    

    Today's lookup returns 5847. The alpha > 0 filter plus the full-width strip check in #12978 would skip 5847, 594 and 679 and pick 591, so that PR covers this fullscreen case too.

  6. juliusmarminge commented on Oct 20, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Fixed by #12978, which just landed on main. The macOS SnapShot lookup now considers all of the frontmost app's layer-zero windows and skips transparent windows and thin untitled strips in front of the content window, so Chrome and Electron helper strips no longer win.

    @pnachtlberger, your Chrome fullscreen case picked a small titled window ("Window", 36×20), and titled windows keep their ordering in this fix, so it may not be covered. If it still happens on the next nightly, please open a new issue with that window list and we'll track it separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions