Skip to content

[Bug]: preview_resize always times out (and evicts the automation host) when the main window is zoomed, because the guest webview reports innerWidth × hostZoom #12319

Description

@Gal-WPsite

Filed by Claude (Fable 5.1, running inside T3 Code) on behalf of Gal Hadad (@Gal-WPsite), at his request. Gal reviewed the summary; the investigation and reproduction below were done by the agent on his Mac.

Before submitting

Area

apps/web (preview automation host in the renderer), with a side effect in apps/server

Steps to reproduce

  1. On macOS, in T3 Code (Alpha) 0.0.42, use View > Zoom In a few times so the main window runs at a zoom level other than 0 (Gal runs at level 2.5, i.e. 1.2 ** 2.5 = 1.577; window.devicePixelRatio in the renderer reads 1.577 on a non-Retina 1920x2160 display).
  2. From an agent, call preview_open with any URL (e.g. https://example.com).
  3. Call preview_resize with { mode: "freeform", width: 1440, height: 900 } (any freeform or preset size reproduces).

Expected behavior

The resize completes and the guest reports a 1440x900 CSS viewport, independent of the main window zoom.

Actual behavior

preview_resize blocks for the full timeout and fails with Preview automation resize timed out after 15000ms. Because PreviewAutomationBroker.awaitResponse disconnects the host on timeout, every later preview/device tool then fails with No preview automation host is available for <op> in environment … until the window is reloaded (View > Reload) or closed and reopened (that part is #12146).

Root cause, read from the bundled renderer in app.asar (function names are the minified ones):

  • The renderer's resize handler polls until XU({ setting, appliedSettingKey, declaredViewport, renderedViewport }) is true, where renderedViewport comes from webview.executeJavaScript("({ width: window.innerWidth, height: window.innerHeight })") and must match the requested CSS size within 1 px.
  • The desktop PreviewManager asserts the guest zoom factor to tab.zoomFactor (default browserDefaultZoomFactor = 1) on registerWebview and again in reapplyZoom whenever DesktopWindow.zoomMain changes the main window zoom.
  • With the embedder at zoom 1.577 and the guest at zoom 1, a <webview> styled width: 1280px (host CSS px) is 2019 device px, and the guest reports innerWidth = 2019. Measured on the affected machine: data-preview-css-width = 1280, guest innerWidth = 2019, innerHeight = 1262. The comparison can never pass, so every resize times out.
  • Side effect even without automation: a "1280 px viewport" really lays out the page at 2019 CSS px, so responsive breakpoints shown in the preview are wrong whenever the UI is zoomed.

Verification of the diagnosis: setting the guest zoom to the host zoom from the renderer (webview.setZoomFactor(window.devicePixelRatio) on this dpr-1 display) makes the guest report 1280x800, and the same preview_resize to 1440x900 then succeeds immediately; a preset resize (iphone-12-pro) and mode: "fill" also succeed. Resetting the guest zoom to 1 brings the timeout back.

Impact

Any user who zooms the T3 Code UI (accessibility, high-resolution portrait monitors, non-Latin scripts) loses all preview automation on the first resize, and the failure mode is a 15 s hang followed by a permanent "no host" state, with no hint that the UI zoom is the cause.

Version or commit

T3 Code (Alpha) 0.0.42 (CFBundleVersion 0.0.42), app.asar dated 2026-09-16.

Environment

macOS (Darwin 25.5.0), Apple Silicon, single 1920x2160 display at scale 1. Agent provider: Codex (when first hit) and Claude Code (reproduction). Local environment, no T3 Connect.

Logs or stack traces

server.trace.ndjson, 2026-09-17 (Asia/Jerusalem), same environment id throughout:

23:50:01 PreviewAutomationBroker.connect                       ok
23:50:36 McpServer tools/call preview_resize {tabId:"tab_3",mode:"freeform",width:1440,height:900}
23:50:36 PreviewAutomationBroker.awaitResponse 15002ms         PreviewAutomationTimeoutError: Preview automation resize timed out after 15000ms.
23:50:51 PreviewAutomationBroker.disconnect                    ok
23:50:51 ws.rpc.previewAutomation.connect (50718ms)            Interrupted
23:50:51 PreviewAutomationBroker.invoke status                 PreviewAutomationNoAvailableHostError
23:50:52 PreviewAutomationBroker.invoke resize                 PreviewAutomationNoAvailableHostError
23:51:12 PreviewAutomationBroker.invoke open                   PreviewAutomationNoAvailableHostError

No new PreviewAutomationBroker.connect appears afterwards until the window is reloaded. desktop.trace.ndjson shows no resize-related PreviewManager span in that window; the request never left the renderer's wait loop.

Screenshots, recordings, or supporting files

Renderer state captured over the local DevTools port while the resize was pending:

{"inner":[532,1349],"dpr":1.5774409770965576,"outer":[840,2129],
 "webview":{"key":"freeform:1280:800:","cssW":"1280","cssH":"800","zoomFactor":1,
            "guestInner":{"width":2019,"height":1262}}}

Workaround

  • View > Actual Size (Cmd+0) before using preview automation; then View > Reload if the host is already gone.
  • Gal's local RTL helper now keeps preview webviews' zoom factor equal to the main window zoom (snapped to Electron's half-level steps), which makes preview_resize pass and restores correct breakpoints. A proper fix would either compare the rendered viewport in host CSS pixels (divide guest innerWidth by the embedder zoom factor), or set the guest zoom to browserDefaultZoomFactor * mainWindowZoomFactor in assertTabZoom/reapplyZoom.

Activity

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

    acceptedfeature request acceptedbugSomething 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