Skip to content

[Bug]: preview_resize times out and leaves viewport state internally inconsistent #3712

Description

@gregbartell

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. Start T3 Code Desktop.

  2. Open a Codex-backed thread with the T3 preview MCP tools available.

  3. Serve any local web page and open it in the preview:

    python -m http.server 8000 --directory build/site
    {
      "show": true,
      "reuseExistingTab": false,
      "url": "http://localhost:8000/index.html"
    }
  4. Call preview_resize in freeform mode:

    {
      "mode": "freeform",
      "width": 1920,
      "height": 1200,
      "timeoutMs": 15000
    }
  5. Check both preview_status and the live DOM viewport:

    ({ innerWidth, innerHeight, devicePixelRatio })
  6. Repeat with mode: "fill" and with the iphone-12-pro preset.

  7. Call preview_snapshot after the resize attempts.

Expected behavior

preview_resize should either:

  • complete successfully and make viewportSetting, measured viewport, live DOM innerWidth/innerHeight, and snapshot screenshot size agree, or
  • fail without partially changing tab state.

If exact sizing is impossible, the tool should return the effective viewport and explain the mismatch.

Actual behavior

Each resize call timed out after 15 seconds but still partially changed state.

After freeform 1920x1200, preview_status reported the requested setting while the measured viewport and live DOM viewport stayed at 1280x800:

{
  "viewportSetting": { "_tag": "freeform", "width": 1920, "height": 1200 },
  "viewport": { "width": 1280, "height": 800 }
}
{
  "innerWidth": 1280,
  "innerHeight": 800,
  "devicePixelRatio": 2.190890312194824
}

Later, the same requested setting drifted to a measured viewport of 2103x1314.

After a timed-out fill resize, measured and live viewport changed to about 410x987.

After a timed-out iphone-12-pro preset resize, viewportSetting changed to 390x844, but measured and live viewport were about 427x924:

{
  "viewportSetting": {
    "_tag": "preset",
    "width": 390,
    "height": 844,
    "presetId": "iphone-12-pro"
  },
  "viewport": { "width": 427, "height": 924 }
}

preview_snapshot also returned a PNG screenshot sized 1280x800 while preview_status reported a measured viewport of 2103x1314.

Impact

Major degradation or frequent failure

Version or commit

T3 Code desktop 0.0.28-1 via t3code-bin AUR package.

Environment

Arch Linux x86_64, kernel 7.0.13-arch1-1, T3 Code desktop AppImage package via t3code-bin, Codex provider.

Logs or stack traces

Representative resize failure:


PreviewAutomationTimeoutError: Preview automation resize timed out after 15000ms.


The important diagnostic is that status/live viewport values diverge after the timeout, as shown above.

Screenshots, recordings, or supporting files

No response

Workaround

After any resize timeout, treat viewport state as unknown. Measure the effective viewport with preview_evaluate using innerWidth and innerHeight, and compute interaction coordinates from live DOM geometry instead of snapshot coordinates.

Activity

  1. added
    bugSomething is broken or behaving incorrectly.
    needs-triageIssue needs maintainer review and initial categorization.
    on Jul 5, 2026
  2. grey-tsosie commented on Aug 27, 2026

    @grey-tsosie

    Still reproduces on 0.0.33, seven weeks after this was filed against 0.0.28.

    Arch Linux x86_64, kernel 7.1.8-arch1-3, Hyprland, t3code-bin AUR package
    from the AppImage, Claude provider via Claude Code as the MCP client.

    All three modes, on a freshly loaded page

    Against a static local page on 127.0.0.1, opened seconds earlier and confirmed
    loaded:

    preview_evaluate {"expression": "JSON.stringify({math: 1+1, w: innerWidth, h: innerHeight})"}
      -> {"math":2,"w":2019,"h":1262}
    
    preview_resize {"mode": "fill"}                                    -> timed out after 15000ms
    preview_resize {"mode": "freeform", "width": 1024, "height": 768}  -> timed out after 15000ms
    preview_resize {"mode": "preset", "preset": "iphone-12-pro", "orientation": "portrait"}
                                                                       -> timed out after 15000ms
    
    preview_evaluate {"expression": "JSON.stringify({math: 2+2, w: innerWidth, h: innerHeight})"}
      -> {"math":4,"w":2019,"h":1262}
    

    preview_evaluate answers correctly immediately before and immediately after
    every failed resize. preview_set_appearance also succeeds against the same tab
    in the same sequence, and its effect reads back from inside the page with
    matchMedia. The tab is not poisoned and the automation channel is not wedged.

    It also timed out on a tab reporting visible: true

    This is the part I think is worth your attention, given how much of #3713 turns
    on tab visibility.

    preview_open {"tabId": "...", "show": true, "open": true, "reuseExistingTab": true}
      -> {"available":true,"visible":true,"tabId":"tab_f","url":"about:blank", ...}
    
    preview_resize {"tabId": "tab_f", "mode": "freeform", "width": 1024, "height": 768}
      -> Preview automation resize timed out after 15000ms.
    
    preview_status {"tabId": "tab_f"}
      -> {"available":true,"visible":true,"tabId":"tab_f", ...}
    

    The status call immediately after the timeout still reported the tab as available
    and visible. So resize failed on a tab that the server itself described as
    visible, which suggests this is not simply another face of #3713.

    I want to be honest about the limit of that evidence. visible: true happened
    exactly once here and I could not reproduce it afterwards. A fresh tab opened
    with "show": true, "open": true, "reuseExistingTab": false came back
    "visible": false, and re-showing the existing tab came back "visible": false
    as well. I have written that up separately on #3713.

    Raising the deadline does not help

    I searched every local session transcript on this machine for preview_resize
    calls and their results. There are ten, spanning 2026-08-14 to 2026-08-27, across
    six sessions and three unrelated projects, plus five more I ran today.

    All of them timed out. Eight of the ten historic calls hit the 15000ms default,
    one hit 30000ms and one hit 45000ms after an explicit timeoutMs. Each failed at
    its own deadline rather than at 15000ms, so this is not a slow operation that
    needs longer. It never completes.

    Arguments Calls
    {mode, width, height} 6
    {mode} 2
    {mode, width, height, timeoutMs} 1
    {mode, timeoutMs} 1

    The package was installed here on 2026-08-11 and the first recorded failure is
    2026-08-14. I have no record of preview_resize ever succeeding on this machine,
    so I cannot say whether this is a regression or has always been broken.

    One difference from the original report

    On the non-visible tab, three consecutive failed resizes changed nothing at all.
    preview_status returned byte-identical output before and after, still reporting
    the pre-existing viewportSetting of freeform 1280x800. The failed call
    neither recorded nor applied the requested setting, where the original report saw
    the requested setting stick.

    What is consistent across every tab I have looked at is that viewportSetting
    and the measured viewport disagree on tabs nobody has successfully resized.
    Across six sessions the stored setting was always freeform 1280x800, while the
    measured viewport was whatever the panel happened to be: 2019x1262,
    1843x1152, 1403x877, 1402x876, 889x555, 1281x801.

    Related

  3. coygeek commented on Oct 5, 2026

    @coygeek

    fix(preview): freeform resize times out on an available browser tab

    Summary

    Supplementary evidence for #3712: three consecutive preview_resize requests for a 560 × 760 freeform viewport timed out in a Codex-backed session. A preceding navigation reported an available, loaded tab with a measured 1280 × 800 viewport. Raising the deadline from 15 to 30 seconds did not produce success in this bounded sample. These records establish the timeout symptom, but do not establish the viewport inconsistency in the original issue or the zoom-related cause in #12319.

    Steps to reproduce

    This is the recorded historical sequence, not a newly executed or minimized reproduction. The exact T3 release at the time of the calls and a known-good resize baseline are unknown.

    1. Navigate the current collaborative preview tab to a local test page. The retained response reports available: true, visible: false, loading: false, and both the freeform setting and measured viewport as 1280 × 800.
    2. Call preview_resize with {"mode":"freeform","width":560,"height":760}.
    3. After its timeout, call preview_status with {}. The retained response still reports an available, loaded tab and the previous 1280 × 800 setting, but omits the measured viewport.
    4. Retry with {"mode":"freeform","width":560,"height":760,"timeoutMs":30000}.
    5. A subsequent preview_open response again reports an available, loaded tab with the previous 1280 × 800 setting and measured viewport.
    6. Retry with {"mode":"freeform","width":560,"height":760,"timeoutMs":15000}.
    7. The next preview_snapshot call with {"includeImage":false} returns PreviewAutomationNoAvailableHostError.

    All three recorded resize attempts failed. No successful resize control was retained in this session. A deterministic rerun requires the historical release, original page fixture, and browser host state during those requests, including host/guest zoom, rendering state, and connection transitions. No browser rerun was performed in this investigation.

    Expected behavior

    The supported freeform resize operation sets the current tab to the requested CSS-pixel dimensions and returns its setting and measured viewport. The currently inspected contract accepts 560 × 760. On an attached, ready tab, the request should complete with the effective viewport matching the requested dimensions within the implementation's one-pixel rounding tolerance.

    Actual behavior

    Attempt Input Recorded lifecycle interval Exact failure text
    A {"mode":"freeform","width":560,"height":760} 15.008 s Preview automation resize timed out after 15000ms.
    B {"mode":"freeform","width":560,"height":760,"timeoutMs":30000} 30.011 s Preview automation resize timed out after 30000ms.
    C {"mode":"freeform","width":560,"height":760,"timeoutMs":15000} 15.006 s Preview automation resize timed out after 15000ms.

    The next snapshot after Attempt C returned PreviewAutomationNoAvailableHostError. This sequence does not prove that resize caused host unavailability. No live DOM viewport or zoom measurements were retained during these requests.

    Evidence

    • Expected source: The inspected Nightly bundle 0.0.46-nightly.20261004.2657 declares the freeform resize operation in apps/server/dist/binCli-B1WajSKX.mjs inside app.asar. Source breadcrumbs at public commit 95030dc674883f0f2a7fd034b32ce742c8cf55d0 are packages/contracts/src/previewAutomation.ts (PreviewAutomationResizeInput and PreviewAutomationResizeResult), apps/server/src/mcp/toolkits/preview/tools.ts (PreviewResizeTool), and apps/web/src/components/preview/previewViewportReadiness.ts (fixed-size matching with one-pixel tolerance). These inspected versions corroborate the input contract; they do not establish the historical failing release.
    • Failure source: Three retained V2 dynamic_tool records named t3-code.preview_resize, shown inline above, plus the preceding navigation, intervening status/open responses, and subsequent snapshot error.
    • Evidence provenance: observed
    • Local verification: not-run
    • Reproduction completeness: incomplete
    • Missing fact: The historical failing release, original page fixture, and browser host state during the requests, including host/guest zoom, rendering state, and connection transitions, are unavailable.

    Read-only inspection of retained tool records supplies the primary failure evidence. Bundle and source inspection separately corroborate the contract. No browser/GUI reproduction was executed; SQLite inspection used a read-only connection with query_only enabled.

    Restoration check

    Recover the historical prerequisites or independently reproduce an equivalent case. Repeat the 560 × 760 request on a ready tab. A passing result is a successful response whose setting and measured viewport match the requested dimensions within one-pixel tolerance, instead of consuming the timeout. Independently verify the live DOM viewport and a subsequent successful status/snapshot call. Compare with a known-good control without assuming zoom is the cause.

    Affected area

    apps/web preview automation renderer and apps/server preview automation broker, used through the desktop collaborative browser.

    Runtime or environment

    The historical records identify the Codex provider and a local test page. They do not retain the exact historical T3 release or OS version. The installation inspected for contract corroboration is Nightly 0.0.46-nightly.20261004.2657.

    Impact

    The three requests consumed approximately 60 seconds across their configured deadlines and returned errors. This bounded sample does not establish population failure frequency.

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.needs-triageIssue needs maintainer review and initial categorization.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions