Skip to content

[Bug]: preview_snapshot always times out for tabs in delegated child threads and for open:false tabs (macOS 0.1.1) #23936

Open

Description

@GeorgieSmile

Before submitting

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

This is the remaining part of #16567, which was closed with the note that background-tab snapshots can still time out because the underlying screenshot capture remains unbounded. The Windows reports (#23139, #17483) describe the same mechanism; this is the macOS / delegated-child case.

Area

apps/desktop

Steps to reproduce

Same tiny static page, all within ~3 minutes:

Caller How the tab was opened preview_snapshot
Parent thread (on screen) open:false timed out, 3 of 3
Parent, same tab then preview_open({tabId, open:true}) OK
Parent, new tab open:true OK
Child thread (delegate_task, Claude Sonnet 5.5) default (no open) timed out
Child, same tab then open:true timed out
Child, new tab open:false timed out
  1. preview_open({url:"http://127.0.0.1:8765/tiny.html", reuseExistingTab:false, open:false})
  2. preview_snapshot({tabId}) fails after about 10 s.
  3. preview_open({tabId, open:true}), then preview_snapshot({tabId}) succeeds.
  4. Have a delegate_task child run steps 1–3. Step 3 still fails, because the child thread is never on screen.

Second repro on a public site: I gave one Claude child (Sonnet 5.5) and one Codex child (GPT-6.1 Sol) the same QA task on https://todomvc.com/examples/react/dist/ without naming any tool. Both chose T3's preview tools first; preview_open and preview_evaluate worked, but preview_snapshot timed out every time (Claude 3 of 3, Codex 2 of 2), and both had to fall back to an external headless browser to finish.

Expected behavior

Snapshots work for background tabs and for tabs opened by delegated child threads. The preview_open description says open=false is for "background-only automation". If that can't be supported, fail immediately with a clear error (like the existing capture-unavailable "present the target tab" message) and document the limitation.

Actual behavior

preview_snapshot succeeds only when the tab is shown in the inline preview of the thread on screen. Otherwise it waits ~10 s and fails with Preview snapshot failed: Preview automation snapshot timed out after 15000ms.

In those same tabs, preview_open, preview_navigate, preview_evaluate, preview_click and t3_preview_close all work, and requestAnimationFrame still fires. Only the snapshot (screenshot capture) hangs.

This breaks the coordinator pattern: a parent agent delegates browser checks to children, and none of them can take a snapshot.

Secondary: the error message is misleading. The server trace shows each failure at ~10,000 ms. The host throws tooBusy() ("The page was too busy to capture a snapshot in time…") from SNAPSHOT_TIMEOUT_MS = 1e4, then classifyResponseError rebuilds it from the broker context, which uses timeoutMs: 15e3. Agents see the wrong duration and lose the real reason.

Impact

Major degradation or frequent failure

Version or commit

T3 Code (Beta) 0.1.1 (also checked: 0.1.2-nightly.20261022.3526 does not include PR #22743)

Environment

macOS 27.0.1, Apple Silicon. Agents: Claude (Opus 5.5 parent, Sonnet 5.5 child via delegate_task), Codex (GPT-6.1 Sol child).

Logs or stack traces

PreviewAutomationBroker.awaitResponse 10003ms Failure PreviewAutomationTimeoutError: Preview automation snapshot timed out after 15000ms.
    at classifyResponseError (.../binCli-DF59J6P3.mjs:310107:48)
PreviewAutomationBroker.respond   # late response arrives ~10 s after the failure

Workaround

The on-screen thread can snapshot with open:true. Child threads can use preview_evaluate for DOM checks, and an external headless browser (e.g. Playwright CLI) for screenshots.

Related

Activity

  1. DrBushyTop commented on Oct 23, 2026

    @DrBushyTop

    Note

    Claude Opus 5.5 posting on behalf of @DrBushyTop

    Repro on macOS while the session is locked and the user is on another machine. Desktop 0.1.3-nightly.20261023.3566 on an Apple Silicon Mac used as a server. The user follows the thread from a second Mac, so the thread is never on this machine's screen. preview_open (with open:true or open:false), preview_navigate and preview_evaluate work, and requestAnimationFrame fires. Every preview_snapshot times out, even on example.com.

    The lock is not the cause. On the same locked session, a standalone Electron 44.9.3 script capturing an animated page with webContents.capturePage() got 3 of 3 distinct fresh frames for each of: a never-shown BrowserWindow, a never-shown one with backgroundThrottling:false, a shown window, and a shown-then-hidden window. So #22743's never-shown BrowserWindow approach should also cover locked or unattended Macs. That case isn't in its test table yet.

    Regression context. Before roughly Oct 21, this setup used the server's headless browser, which works while locked. Now the server always gets desktop browser file descriptors when the desktop app launches it, so agent tabs land in parked webviews. No setting turns this off.

  2. Prosta4okua commented on Oct 23, 2026

    @Prosta4okua

    Also reproduces on Linux, nightly build, panel open, not a delegated child thread

    • Version: 0.1.3-nightly.20261023.3579 (desktop AppImage), Linux x64 (Fedora, kernel 7.2.9). This build includes fix(desktop): reduce app crashes when a preview tab's renderer dies during agent screenshots #24056.
    • The thread is a regular one created from the UI (not delegate_task). The user confirmed the browser panel was open in the thread during the attempt. The agent still saw all of its tabs with visible: false.
    • preview_snapshot fails every time in this session: Preview snapshot failed: Preview automation snapshot timed out after 15000ms.
    • Reading page data works. Broker calls made about 5 s before the failure succeeded (450 ms, 4 ms, 2 ms).
    • Server trace (paths removed):
      • PreviewAutomationBroker.awaitResponse: 10009 ms, Failure.
      • PreviewAutomationTimeoutError: Preview automation snapshot timed out after 15000ms with [cause]: Error: The page was too busy to capture a snapshot in time. Wait for it to settle and take another snapshot.
      • This is the same 10 s vs 15 s mismatch described under "Secondary" in the issue body.
    • Server startup in the same trace logs PreviewBrowserHost.sandboxBlocked. I don't know whether it is related.

    The page the user had open is not disclosed.

    Prepared via t3 triage (Claude Sonnet 5.5, Claude Code).

  3. marcellocurto commented on Oct 24, 2026

    @marcellocurto

    Note

    Claude Opus 5.5 posting on behalf of @marcellocurto

    Still reproduces on 0.1.2 stable (macOS 26.6.2 arm64, Electron 44.9.3). This is the desktop app with its local server and the Claude agent provider.

    How often. Since the update to 0.1.2 on Oct 23, all 18 preview_snapshot calls in my provider logs have failed. They came from 8 threads, each running in a local worktree. Every one returned after about 10 s with Preview automation snapshot timed out after 15000ms. Text-only calls (no includeImage) failed the same way.

    Fresh reproduction:

    1. preview_open({url:"https://example.com", open:false, reuseExistingTab:false}) returned with visible:false and loading:false.
    2. preview_snapshot({tabId}), with no image requested, failed after 10,008 ms. The server span PreviewAutomationBroker.awaitResponse records the same error.
    3. preview_evaluate on the same tab succeeded right away. It reported visibilityState:"visible", hidden:false, a 1280×800 viewport, and requestAnimationFrame fired.
    4. preview_open({..., open:true, reuseExistingTab:false}) in the same thread also returned visible:false, because I wasn't viewing the thread at the time. Its snapshot failed the same way.

    While the snapshots were failing, the desktop trace recorded no PreviewManager.captureScreenshot span. So the hang is in the server-browser CDP capture path (ServerBrowserPage.capture), as described in #22743. The 10 s duration matches SNAPSHOT_TIMEOUT_MS, while the error message reports the broker's 15 s budget (#24130).

    #21494 would fix the text-only case, which was most of these calls.

  4. Clickist commented on Oct 24, 2026

    @Clickist

    Repro on 0.1.2 stable (macOS, pi provider) — plus the failing hop in the desktop trace

    Environment: macOS 26.6.2 (25G83), arm64, T3 Code 0.1.2 stable (Electron 44.9.3), t3 v0.1.2, provider pi, local server launched by the desktop app.

    Rate: 9 of 9 preview_snapshot calls failed. Nothing succeeds, including text-only (no includeImage).

    Everything below happened in one thread that was active and on screen for the whole session:

    Tab Opened with visible snapshot
    default profile, example.com open:false false timeout
    default profile, baidu.com open:true false timeout
    incognito, example.com open:true false timeout
    fresh tab after full app restart open:true false timeout
    fresh tab after opening and closing DevTools open:true false timeout

    Every attempt ends with Preview snapshot failed: Preview automation snapshot timed out after 15000ms. preview_open reports visible: false in all of them, including open: true with reuseExistingTab: false.

    Ops that still work on the same tabs: preview_navigate, preview_type + preview_press (filled a search box and submitted, got results), preview_evaluate. preview_click times out like snapshot.

    Desktop trace (userdata/logs/desktop.trace.ndjson):

    PreviewManager.createControlSession     Success   <- at tab creation
    PreviewManager.initializeControlSession Success
    ...
    PreviewManager.detachControlSession     Success   <- scope finalizer
    PreviewManager.recoverDetachedControlSession Success
    PreviewManager.ensureControlSession     Failure :: PreviewOperationError: Desktop preview operation failed: initializeDebugger.defaultBackground (WebContents N)
    PreviewManager.createControlSession     Failure :: same
    PreviewManager.initializeControlSession Failure :: same
    

    N differs per tab (2, 3, 4, 6, 7), so this is not one poisoned WebContents. The order repeats for every tab: the first control session succeeds, gets detached, and the re-attach never succeeds again.

    Server side matches the timeout described in the report:

    PreviewAutomationBroker.awaitResponse  Failure  PreviewAutomationTimeoutError: Preview automation snapshot timed out after 15000ms.
    

    Code reading (app.asar, PreviewManager.createControlSession):

    yield* attempt({ operation: "attachDebuggerListeners", ... }, () => {
      wcDebugger.on("message", onMessage);
      wcDebugger.on("detach", onDetach);
      wcDebugger.attach("1.3");
    });
    yield* attemptPromise({ operation: "initializeDebugger.defaultBackground", ... }, () =>
      wcDebugger.sendCommand("Emulation.setDefaultBackgroundColorOverride", { color: { r: 255, g: 255, b: 255, a: 1 } }));

    attach() is wrapped in attempt (error swallowed) while the follow-up sendCommand is what surfaces. So when the re-attach is rejected — the usual Another debugger is already attached to the webContents — the error that reaches the trace is initializeDebugger.defaultBackground, and every CDP-dependent operation dies with it (Page.captureScreenshot, the accessibility tree, Input.dispatchMouseEvent). DOM-level ops go through executeJavaScript and keep working, which matches the observed split exactly.

    Workaround for other agents hitting this: preview_evaluate covers reading, form filling and el.click(); only screenshots and real mouse events are lost.

    Happy to run a nightly with a fix through a macOS + pi provider check if that helps.

  5. Clickist commented on Oct 24, 2026

    @Clickist

    Correction to my trace reading above

    After reading #24133 I'm withdrawing the "CDP debugger re-attach is rejected" inference I made. The PR description explains the mechanism better: inactive preview webviews are moved offscreen to (-100000, -100000), Electron stops compositing a guest that lies fully outside the window, and Page.captureScreenshot then waits for a frame that never arrives.

    My initializeDebugger.defaultBackground failure is consistent with that same root cause surfacing in a different call, not with a competing explanation. Pulling the inference so it doesn't mislead anyone triaging: the trace still stands, only my interpretation of it was wrong.

    (preview_evaluate, preview_navigate, preview_type/preview_press keep working because they never wait on a compositor frame.)

  6. Clickist commented on Oct 24, 2026

    @Clickist

    Retracting one line from my report above

    I wrote that preview_click times out like snapshot. That was wrong, and I retested before anyone spends time on it.

    What actually happened: both of my click timeouts (timed out after 15000ms and timed out after 30000ms, same message, only the budget differed) happened on one tab whose history was:

    1. preview_open({open:false, url:"https://example.com"})
    2. preview_open({tabId, open:true})
    3. preview_resize({mode:"freeform", width:1280, height:900})
    4. then preview_click({locator:'a[href^="https://www.iana.org"]'}) → timeout, twice

    Retest on clean tabs just now (never open:true'd again, never resized), both visible:false:

    op open:false tab open:true tab
    click on a ✅ navigated to iana.org ✅ navigated to iana.org
    snapshot ❌ 15000ms timeout —
    scroll ✅ —
    evaluate ✅ innerWidth/Height 1280×800, visibilityState:"visible" —
    hover (a, a[href], role=link) ❌ invalid locator (1/7/9 characters) —
    resize(1280×900) ⚠️ reports setting:1280×900, actual viewport 1280×800 —

    An independent session on the same machine and server also reports click/navigate/evaluate/type/press/scroll/hover/wait_for/set_appearance all working, with only snapshot and the real viewport behind resize broken.

    So the split is narrower than I first wrote: preview_snapshot alone is the reliable failure. Click working or not looks environmental (tab history / whether it was resized), not part of the snapshot path. Treat my earlier "click times out too" as noise.

    Two things I noticed while retesting that may be worth their own issues:

    • preview_hover only accepts aria-ref=<ref>; CSS selectors and role= are rejected as invalid locators. Since refs can only come from a snapshot, hover is unusable exactly when snapshots are broken.
    • preview_resize silently clamps to the host window (asked 900, got 800) and still reports the requested size in setting.

    Also seen once: preview_status returned available:false with all tabs null, and a fresh preview_open recovered it — the browser host drops out briefly.

  7. adrazz-cyber commented on Oct 25, 2026

    @adrazz-cyber

    Additional Stable 0.1.2 reproduction: three delegated callers and parent controls

    Reproduced on 25 October 2026, 02:07–02:16 UTC, using a small local static page with no external resources. Fresh incognito tabs were used for every case; the three callers' browser operations were serialised and each closed its two tabs. The parent also repeated its control on example.com after the child tests.

    Environment

    • T3 Code desktop product name: T3 Code (Beta); desktop and local-server version: 0.1.2, the published stable release.
    • macOS 27.0.1, Apple Silicon/arm64.
    • Live page user agent: Electron 44.9.3 / Chromium 152.0.7977.167.
    • Parent: GPT-6.1-Sol through Codex. Delegated test callers: Claude Opus 5.5 through Claude, Grok 4.7 through Grok, and Gemini 3.8 Flash High through Antigravity. All used T3's own preview MCP tools.

    Observed results

    Each cell is one fresh-tab snapshot attempt with includeImage:false; there were no snapshot retries.

    Caller / page Requested open:false Requested open:true DOM evaluation
    Parent / local fixture Timeout, 10.0 s Success, 110 ms tool wall time Readiness/title read successfully before and after the background failure
    Opus 5.5 child / local fixture Timeout, 10.0 s Timeout, 10.0 s Successful before and after both failures
    Grok 4.7 child / local fixture Timeout, 10.0 s Timeout, 10.0 s Successful before and after both failures
    Gemini 3.8 Flash High child / local fixture Timeout, 10.0 s Success: correct fixture accessibility tree and 1280×800 PNG metadata Successful before and after both snapshots
    Parent / example.com, after child tests Timeout, 10.0 s Success, 121 ms tool wall time Successful reads before both snapshots

    The Gemini open:true result is included deliberately: this run does not support a universal claim that every delegated-child snapshot fails. The parent controls also show that the browser was capable of returning snapshots during this session.

    Every timeout returned:

    Preview snapshot failed: Preview automation snapshot timed out after 15000ms.
    

    Server PreviewAutomationBroker.awaitResponse failures associated with the local-fixture calls by UTC timing were:

    Caller / requested mode Server start UTC Server duration (ms)
    Parent / false 02:07:03.404826 10005.452
    Opus / false 02:08:11.401145 10001.912
    Opus / true 02:08:41.593320 10002.267
    Grok / false 02:12:06.453214 10002.578
    Grok / true 02:13:00.440206 10001.996
    Gemini / false 02:14:42.050173 10002.055

    The error therefore reports 15 seconds while the corresponding server spans end at about 10 seconds. The parent's failed span also retained the cause The page was too busy to capture a snapshot in time. Wait for it to settle and take another snapshot. These spans did not include tab IDs, so the association above uses their timestamps and the serial call records; it is not an ID-based join. No guessed subtraction of model or harness overhead is used.

    Both successful and failed cases returned preview metadata visible:false; the evaluated pages reported document.visibilityState:"visible" and readyState:"complete". Those flags alone did not predict the result. We did not instrument real window/panel visibility or manually switch to the child threads, so requested open:true is not claimed as proof of an on-screen child panel.

    Reproduction

    Save the fixture below as tiny.html, serve its directory on loopback (for example python3 -m http.server 8765 --bind 127.0.0.1), and run these in the parent and then in a delegate_task child. Use a separate new tab for each requested open mode.

    {"url":"http://127.0.0.1:8765/tiny.html","open":false,"reuseExistingTab":false,"profileId":"incognito"}
    1. Pass that object to preview_open, retaining its returned tabId.
    2. On that tab, use preview_evaluate to read ({title:document.title,readyState:document.readyState,visibility:document.visibilityState}).
    3. Call preview_snapshot({tabId,includeImage:false}) once.
    4. Read the title/readiness with preview_evaluate again, then close that tab with t3_preview_close.
    5. Repeat on a new tab with open:true.
    Exact local fixture
    <!doctype html>
    <html lang="en"><meta charset="utf-8"><title>T3 browser snapshot reproduction</title>
    <style>body{font:24px system-ui;margin:48px;background:#e5f2ff;color:#14253a}button{font:inherit;padding:12px 24px}output{display:block;margin:24px 0}</style>
    <h1>T3 browser snapshot reproduction</h1>
    <p>This page has no external resources or application framework.</p>
    <p id="case"></p><button id="counter" type="button">Increment counter</button><output id="value">0</output>
    <script>document.querySelector('#case').textContent=location.search;document.querySelector('#counter').onclick=()=>{document.querySelector('#value').textContent=String(Number(document.querySelector('#value').textContent)+1)};</script></html>

    These model callers share the same T3 browser service: matching failures are not independent rendering implementations or proof that every preview timeout has one root cause. No app patch, permission change, app restart, release-channel switch or external-browser fallback was used. The current Nightly was researched but not installed or runtime-tested. This adds a current Stable reproduction and the successful Gemini counterexample to this existing report; it is not a proposed application-code change.

    Prepared by Ledger (GPT-6.1-Sol / Codex) with actual delegated browser calls from Opus 5.5, Grok 4.7 and Gemini 3.8 Flash High. Raw tool results and the focused trace extracts were retained locally; the comment excludes unrelated session logs and personal/client data.

  8. OsirisMedici commented on Oct 25, 2026

    @OsirisMedici

    Additional macOS installed-app evidence, outside a delegated child thread.

    On T3 Code Nightly 0.1.2-nightly.20261022.3512, Electron 44.9.3, a fresh explicitly selected Default tab opened this public repository with open:false. Status reported available:true,visible:false. Evaluation returned the expected page, a complete document and an authenticated-site indicator.

    A snapshot with includeImage:false timed out with Preview automation snapshot timed out after 15000ms. Evaluation still succeeded afterward.

    Calling preview_open on the same tab with open:true,show:true continued to report visible:false. A second snapshot with includeImage:true,save:true timed out identically; evaluation remained usable. The document itself reported visibilityState:"visible", which is distinct from whether the T3 panel is shown.

    This confirms the failure to obtain snapshots in the observed off-screen state. It does not establish an on-screen success comparison, a delegated-child-specific cause, or the rendering/relay failure stage. #24812 is another possible explanation; no reconnect was intentionally triggered or traced.

    We also recorded intermittent snapshot/capture-page failures during an earlier UI audit. The installed app was not patched or restarted for this check.

    Posted by Codex at Osiris's request.

    Follow-up with a synthetic changing-marker fixture on the same installed build:

    • Served two loopback HTML pages with Cache-Control: no-store: a red RED-A page and a blue BLUE-B page. Each uses two animation frames before setting a PAINT READY indicator.
    • Opened a fresh explicit Default tab with open:true,show:true. The tab still reported visible:false.
    • Evaluation on page A returned marker RED-A, background rgb(180,20,36) and paint-ready true. preview_snapshot(save:true,includeImage:true) returned the same 15000ms timeout.
    • Navigated that exact tab to page B. Evaluation returned marker BLUE-B, background rgb(23,73,168) and paint-ready true. The same snapshot call timed out again.
    • Native UI recovery encountered noWindowsAvailable; the supported recording-start operation also timed out.

    Neither snapshot returned a PNG path. This establishes the failure on a static marker fixture, but cannot establish that saved image bytes are stale because none were produced. No total navigation/evaluation disconnect or reconnect trigger was observed.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions