Repository navigation
Description
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
-
Start T3 Code Desktop.
-
Open a Codex-backed thread with the T3 preview MCP tools available.
-
Serve any local web page:
python -m http.server 8000 --directory build/site
-
Open the page in a fresh preview tab:
{ "show": true, "reuseExistingTab": false, "url": "http://localhost:8000/index.html" } -
Confirm the page is loaded with
preview_status. -
Call
preview_snapshot. -
Retry
preview_snapshotif the first call fails. -
Call a simple
preview_evaluateafterward:({ href: location.href, ready: document.readyState })
Expected behavior
On a loaded page, preview_snapshot should return page state or a clear recoverable error.
A snapshot failure should not poison the tab. Follow-up preview_evaluate should continue to work, and preview_open(show: true) should recover the tab if the preview needs to be reattached.
Actual behavior
On a loaded page, the first snapshot returned a generic execution error:
{
"error": {
"_tag": "PreviewAutomationExecutionError",
"operation": "snapshot",
"failureCount": 1
}
}A retry timed out after 15 seconds:
{
"error": {
"_tag": "PreviewAutomationTimeoutError",
"operation": "snapshot",
"failureCount": 1
}
}A simple preview_evaluate immediately afterward also timed out:
PreviewAutomationTimeoutError: Preview automation evaluate timed out after 15000ms.Reopening the same tab with preview_open(show: true) did not restore evaluation in this run. Creating a fresh tab did restore evaluation.
In another run, snapshot failed with an UnknownVizError in the action timeline, while evaluation stayed responsive. This suggests there may be more than one snapshot failure mode.
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 timeout:
PreviewAutomationTimeoutError: Preview automation evaluate timed out after 15000ms.Representative snapshot error:
{
"error": {
"_tag": "PreviewAutomationExecutionError",
"operation": "snapshot",
"failureCount": 1
}
}Screenshots, recordings, or supporting files
No screenshot included. The page was loaded and inspectable by status before snapshot; the useful evidence is the snapshot/evaluate error sequence.
Workaround
Use preview_evaluate and preview_status for inspection when a full snapshot is not required. If snapshot or a follow-up evaluation starts timing out, abandon that tab and open a fresh one.
Activity
daemon-james commentedon Aug 3, 2026
Confirmed on T3 Code
0.0.31on Linux with the Codex provider.During a dashboard inspection session:
preview_snapshottimed out whilepreview_statusstill reported the page as loaded.preview_evaluateandpreview_navigatecalls also timed out, and preview action entries remained in a running state.t3 serveprocess sustained roughly 100–146% CPU and about 2.1 GiB RSS during the degraded period.t3 serveCPU fell to about 3% and preview calls recovered.This adds a server-side resource symptom to the existing tab-poisoning report. It suggests timed-out preview automation may leave queued or stalled work inside T3, rather than the target application being responsible. I avoided further retries once this was isolated, since repeated calls appeared to make the degraded period longer.
JorgeMenaDev commentedon Aug 7, 2026
Confirming this still reproduces on 0.0.32-nightly.20260807.1022 (macOS desktop), with what looks like a deterministic trigger: the tab must be visible.
preview_openwith{"open": false}→preview_snapshot→Preview snapshot failed.(reproduced ~10 times today across 3 models and 2 MCP clients)preview_openwith{"open": true}→preview_snapshot→ works perfectly: PNG plusvisibleText,interactiveElements, full accessibility tree, console and network entries.Suggestion, separate from the underlying cause: the client-facing error is opaque.
previewSnapshotFailureinapps/server/src/mcp/McpHttpServer.tslogs the realerrorTagserver-side viaEffect.logWarning, but sends only the fixed string"Preview snapshot failed.". Callers cannot distinguish "the tab isn't rendered" from a genuine capture failure, and the server logs aren't persisted to disk, so there's no way to recover the tag after the fact. SurfacingerrorTagin the text (it's already instructuredContent) would have saved us a lot of guessing.Impact: background/headless agent threads always have
visible: false, so visual verification is unavailable to automated agents. DOM inspection viapreview_evaluatestill works and covers most of the need.— Jorge Mena
marijnbent commentedon Aug 16, 2026
same for me!
areidyOTH commentedon Aug 24, 2026
Confirming this failure mode on T3 Code Desktop
0.0.34-nightly.20260824.1172on Linux, with Codex driving a visible previewthrough the
t3-codeMCP server.This occurrence adds process-level evidence and narrows one likely expensive path.
Reproduction
preview_snapshotbefore the page has rendered fully. It returns normally.preview_snapshotagain.The first snapshot completed in 80.84 ms. The second MCP call timed out after
15.03 seconds, while the corresponding desktop operation continued for 47.83 seconds
and was recorded as successful.
Afterward:
preview_status,preview_navigate, andpreview_open(reuseExistingTab: false)calls timed out.survived.
Trace evidence
By source order, the 31.37-second command is
Accessibility.getFullAXTree.At the affected tag,
PreviewManager.captureAutomationSnapshotcapsinteractiveElementsat 200 andvisibleTextat 20,000 characters, but calls:without CDP's optional
depthparameter, then includes the complete result asaccessibilityTree.This is a strong candidate for the pathological renderer work, but the available
evidence does not prove it is the sole allocator.
wc.capturePage()runs concurrentlywith the AX-tree request and is not separately timed in this trace, while the screenshot
resize happens only after capture. The two 14.1-second enable calls also show that the
renderer was already severely degraded before
getFullAXTreebegan.Timeout mismatch
The MCP broker defaults to 15 seconds. When that timeout expires it removes the pending
request, but there is no cancellation message to the web host or desktop operation.
The host Promise and CDP request therefore continue. A late success response is ignored
because its pending broker entry no longer exists.
The desktop trace consequently records the 47.8-second snapshot as successful even
though the MCP caller was told it failed after 15 seconds.
One correction to an earlier interpretation:
Accessibility.disableis not a cleanupstep skipped specifically because of this timeout. The snapshot path does not schedule
it at all; the debugger/control session is intentionally persistent until a separate
detach event.
Suggested direction
Accessibility.getFullAXTreea conservativedepth, or query selected nodeswith
getPartialAXTree; additionally bound the returned node array before crossingthe MCP boundary.
operation and releases or resets the affected control session.
capturePage()separately.PreviewManager.sendCommandtrace attributes.renderer responding.
Related but distinct: #7410 / #7408 bounds snapshot metadata at the MCP response
boundary. That protects provider context but does not currently bound the desktop
renderer’s full AX-tree query.
Diagnosed by Codex (GPT-5) via
t3 triage.ezzy1630 commentedon Aug 26, 2026
Confirming on macOS 15 (darwin arm64 25.6.0), desktop
0.0.35-nightly.20260826.1193with the Claude provider. This reproduces @JorgeMenaDev'sopen: falsetrigger, and the desktop traces on this machine let me add the mechanism behind the "leaves tab automation unusable" half of the report.The
open: falsetrigger holdsAcross one session, every
preview_openwith"open": falseproduced a tab that could not be snapshotted; the two calls with"open": truewere fine.preview_open,preview_navigate, andpreview_statusnever failed — only the operations that need a painted frame or a ready overlay.The desktop-side cause is visible in the trace:
capturePagerejects withError: UnknownVizError, which is the same failure mode noted in the original report.1. The client's wait deadline equals the server's, so the useful error can never arrive
waitForDesktopOverlayinapps/web/src/components/preview/PreviewAutomationHosts.tsx:87is handedrequest.timeoutMs:That
timeoutMsis the same 15,000 ms the broker is already counting down (apps/server/src/mcp/PreviewAutomationBroker.ts:429,input.timeoutMs ?? 15_000). For a hidden tab the overlay never reportsavailable, so the loop runs to the full deadline and throwsPreviewAutomationOverlayTimeoutErrorat the exact moment the broker has already discarded the pending deferred.The specific, actionable error is therefore unreachable by construction. Callers only ever see the generic
PreviewAutomationTimeoutError. A client-side deadline meaningfully shorter than the server's would surface "the preview overlay never became available" instead.This compounds the opacity @JorgeMenaDev already flagged at
apps/server/src/mcp/McpHttpServer.ts:121, wherepreviewSnapshotFailurelogs the realerrorTagand then sends only the fixed string"Preview snapshot failed.".2. Head-of-line blocking is why one bad snapshot poisons the tab
withControlSessionruns every action under a single per-tab permit (apps/desktop/src/preview/Manager.ts:1166, ending incontrol.semaphore.withPermit(...)), and nothing on the desktop side has a timeout. So a stalled call blocks every later call, which then burns its own full 15 s server budget without ever executing.Two consecutive
evaluatecalls from the desktop trace, sorted by start time:The second call spent 21,294 of its 21,295 ms waiting for the permit and under 1 ms executing. Both ended within 2 ms of each other. The server had abandoned both at their own 15 s marks.
This is the same shape as @areidyOTH's "MCP call timed out after 15.03 s while the desktop operation continued for 47.83 s", and it explains the tab-poisoning: the caller sees N consecutive timeouts, but only the first one was actually slow.
3. The server records these as successful spans
Worth noting for anyone grepping traces: the failures exit
Successat the span level, because the MCP layer returns anisErrorresult rather than failing the effect.Timeline from this session
For the four evaluates from 05:32:51 onward, the desktop trace shows a single
automationStatuscall at each timestamp and noautomationEvaluateat all — consistent withwaitForDesktopOverlayspinning to its deadline and the request never being dispatched.Still present on
mainPreviewAutomationHosts.tsx,PreviewAutomationBroker.ts,Manager.ts, andMcpHttpServer.tsare byte-identical between tagv0.0.34andmainatb0a0281, so this is not fixed in any newer release.Environment
0.0.34, desktop app0.0.35-nightly.20260826.1193(version skew was present on this machine)localhost:3000Investigated by claude (opus-5) via
t3 triage.grey-tsosie commentedon Aug 27, 2026
Confirming the failure mode on
0.0.33, Arch Linux x86_64, kernel7.1.8-arch1-3, Hyprland,t3code-binAUR package from the AppImage, Claudeprovider via Claude Code.
The reason I am commenting is that the visibility trigger @JorgeMenaDev
identified is the right lead, but on this machine I cannot get a visible tab at
all, by any documented route. If that holds for other Linux users, then
open: trueis not a usable workaround here.open: truenever produced a visible tabEvery
preview_openwith"open": trueon this install has returned"visible": false, across six sessions and three projects. The page loads, thetitle is correct,
loadingisfalse, andpreview_evaluateworks against it.The tab simply never reports visible, so it is never capturable.
show: trueproduced one visible tab and I could not reproduce itOne call did return
"visible": true:I have not managed it again. Two direct attempts afterwards both came back
"visible": false:The same tab that reported
"visible": truereported"visible": falsea fewminutes later without being touched. So whatever sets that flag here is transient
and is not controlled by
openorshowin any pattern I could find.A note for anyone testing this from the client side
I tried using
preview_clickas a cheap proxy for "is the overlay painted",since click needs a painted surface in the way snapshot does. It is not usable
for that.
preview_clickreturns the same result on a visible tab and on anon-visible one, because its reply fails schema validation at the client before
any outcome is visible:
That is an
effect4.0.0-beta.103defect rather than yours. It builds everyMCP reply with
typeof result.encodedResult === "object", and JavaScript reports"object"fornull, so any tool of yours that returns void serializes tostructuredContent: null. I filed it upstream as Effect-TS/effect#7494. Imention it here only so nobody else wastes time treating a click result as
evidence of overlay state.
Scope
preview_resizealso times out here, including on the one tab that did report"visible": true. That looks like a separate cause rather than another instanceof this issue, so I have put that evidence on #3712 instead.
ElliotDrel commentedon Aug 30, 2026
Reproduced on Windows 11 (build 10.0.26200.0), T3 Code Nightly
0.0.37-nightly.20260829.1223, via themcp__t3-code__preview_*tools exposed to a Claude Code agent session (no thread-switching involved, so this isn't the #6355 trigger — the tab simply went bad on its own after repeated snapshot failures).UnknownVizError, reproduced with actionTimeline evidence:
On a freshly opened tab (
preview_open→preview_navigatetohttps://example.com), the firstpreview_snapshotcall failed with only"Preview snapshot failed."surfaced to the caller. A secondpreview_snapshotcall on the same tab succeeded, and its response'sactionTimelineretroactively revealed what actually happened to both attempts:{"id":"browser-action-mtf80yum-f","action":"snapshot","status":"failed","startedAt":"2026-08-30T02:59:32.590Z","completedAt":"2026-08-30T02:59:32.599Z","error":"UnknownVizError"}, {"id":"browser-action-mtf811l9-g","action":"snapshot","status":"failed","startedAt":"2026-08-30T02:59:36.141Z","completedAt":"2026-08-30T02:59:48.457Z","error":"UnknownVizError"}, {"id":"browser-action-mtf81ghy-h","action":"snapshot","status":"running","startedAt":"2026-08-30T02:59:55.462Z"}Note the second failure took ~12.3s to resolve (not an instant rejection), and neither failure's real error tag (
UnknownVizError) was visible anywhere in the tool's own error response — only in a later successful call's timeline. This matches the opacity problem described in #8257.Tabs going fully unusable without a thread switch:
After several of these snapshot retries across three separate tabs (each independently opened via
preview_openwithreuseExistingTab: false, never revisited after a thread change — there was no thread change),preview_statuson all three previously-healthy tabs simultaneously started returning:{"available":true,"visible":false,"tabId":null,"url":null,"title":null,"loading":false}i.e.
available: truebut every identifying field null — self-contradictory, and there was no explicit error to act on. Retryingpreview_statuswith notabId(agent's "current tab") returned the same null-everything shape. The only recovery waspreview_openwithreuseExistingTab: falseto mint a brand-new tab, which worked immediately and normally.This suggests the "poisoned tab" failure mode in this issue and in #6355/#8257 isn't exclusive to the hidden-tab (
open: false) trigger or to leaving/returning to a thread — it can also arise from ordinary snapshot retries alone, and can take out multiple independently-created tabs at once rather than just the one being retried.juliusmarminge commentedon Sep 5, 2026
Fixed by merged #4685 — capturePage/screenshot/snapshot attempts are bounded with retries and guest-identity checks; hung captures release control so later automation is not poisoned.
fix(fork): the updater dispatches and builds only upstream releases w…