pingdotgg / pingdotgg/t3code

[Bug]: Leaving a thread detaches its browser preview and can leave automation unusable

Open
#6,355 2 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

Before submitting
  • I searched existing issues and did not find an exact duplicate.
  • I included enough detail to reproduce or investigate the problem.
Area

apps/desktop

Summary

👋 hey, i'm the human verifying the agent slop below. it's a real problem i keep running into. 😅

When I navigate away from a thread that has an active embedded browser preview, T3 Code appears to detach the preview's control session and listeners.

After returning to the thread, the old preview tab may still exist, but browser automation becomes unreliable or completely unusable. preview_snapshot can fail with UnknownVizError or remain stalled for several minutes. Reusing or reopening the affected tab does not reliably recover it; creating a fresh preview tab does.

This appears related to #3713, #3717, and #3718, but those issues do not identify switching away from a thread as the trigger.

Steps to reproduce
  1. Open a Codex-backed thread in T3 Code Desktop.
  2. Open an embedded browser preview in that thread.
  3. Confirm that preview automation works, for example with preview_status, preview_snapshot, or preview_evaluate.
  4. Leave the thread by selecting another thread in the T3 Code sidebar.
  5. Return to the original thread.
  6. Attempt to inspect or interact with the existing preview tab.
  7. Retry preview_snapshot or another automation operation if the first call fails.
Expected behavior

Leaving and returning to a thread should not invalidate its browser preview.

If T3 Code intentionally suspends or detaches previews belonging to hidden threads, returning to the thread should reattach the preview and restore automation automatically.

At minimum, the tool should return a clear, recoverable error explaining that the tab must be reattached or recreated.

Actual behavior

After the thread loses focus:

  • T3 Code logs successful PreviewManager.detachControlSession and listener-detachment operations.
  • Later preview_snapshot calls against the affected thread's tab fail with UnknownVizError.
  • Some failed snapshot operations remain pending for approximately 76–320 seconds.
  • Subsequent automation against the same tab may remain unusable.
  • Reopening or reusing the existing tab does not reliably recover it.
  • Creating a fresh preview tab restores automation.

The browser backend itself remains available: preview_status still reports automation capability, and new tabs can be created successfully. The failure therefore appears scoped to the detached thread-bound tab rather than to the global browser backend.

Impact

Major degradation or frequent failure.

Long-running agent work can lose access to its browser merely because the user visits another thread. The agent may then spend several minutes retrying a poisoned tab or incorrectly conclude that the in-app browser is globally unavailable.

This especially affects workflows where an agent continues running in the background while the user checks other threads.

Version or commit

T3 Code Nightly:

0.0.34-nightly.20260812.1072

Environment
  • T3 Code Desktop
  • macOS
  • Codex provider
  • Embedded collaborative browser/preview tools
Logs or stack traces

Representative failure:

PreviewOperationError: Desktop preview operation failed:
automationSnapshot.capturePage
[cause]: Error: UnknownVizError

One representative snapshot operation remained pending for approximately 320 seconds before failing:

PreviewManager.captureAutomationSnapshot
durationMs: 320528.876875
[cause]: Error: UnknownVizError
Sanitized trace attachment (NDJSON)

The excerpt below was derived from the local desktop trace. It contains no page content and has been sanitized by removing absolute timestamps, usernames, filesystem paths, URLs, and all thread, project, session, trace, span, and tab identifiers.

SHA-256 of the sanitized NDJSON: 09c63b5853281ad30be7639ef7a4279bdd47ba0231c6ed8db21850e813afe7d6

{"recordType":"metadata","schema":"t3code-sanitized-preview-trace-v1","platform":"macOS","appVersion":"0.0.34-nightly.20260812.1072","sanitization":["absolute timestamps replaced by relative offsets","thread, project, session, trace, tab, and span identifiers removed","usernames and filesystem paths removed","URLs and page content removed","stack frames removed"]}
{"recordType":"event","offsetMs":0,"durationMs":11.835042,"component":"PreviewManager","operation":"captureAutomationSnapshot","result":"Failure","target":"thread_preview_tab_A","error":"UnknownVizError"}
{"recordType":"event","offsetMs":637600.796,"durationMs":114534.930542,"component":"PreviewManager","operation":"captureAutomationSnapshot","result":"Failure","target":"thread_preview_tab_A","error":"UnknownVizError"}
{"recordType":"event","offsetMs":966494.677,"durationMs":76050.029792,"component":"PreviewManager","operation":"captureAutomationSnapshot","result":"Failure","target":"thread_preview_tab_A","error":"UnknownVizError"}
{"recordType":"event","offsetMs":1203748.589,"durationMs":320528.876875,"component":"PreviewManager","operation":"captureAutomationSnapshot","result":"Failure","target":"thread_preview_tab_A","error":"UnknownVizError"}
{"recordType":"event","offsetMs":1226431.167,"durationMs":1.884792,"component":"PreviewManager","operation":"detachControlSession","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226433.093,"durationMs":0.168417,"component":"PreviewManager","operation":"detachListeners","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226434.49,"durationMs":113.926,"component":"PreviewManager","operation":"detachControlSession","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226434.535,"durationMs":0.072708,"component":"PreviewManager","operation":"detachListeners","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226435.258,"durationMs":173.96875,"component":"PreviewManager","operation":"detachControlSession","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226435.273,"durationMs":0.202583,"component":"PreviewManager","operation":"detachListeners","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226437.351,"durationMs":212.145625,"component":"PreviewManager","operation":"detachControlSession","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226437.385,"durationMs":0.053125,"component":"PreviewManager","operation":"detachListeners","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226437.727,"durationMs":217.207833,"component":"PreviewManager","operation":"detachControlSession","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":1226437.733,"durationMs":0.11675,"component":"PreviewManager","operation":"detachListeners","result":"Success","target":"preview_lifecycle","error":null}
{"recordType":"event","offsetMs":2140260.862,"durationMs":8.101542,"component":"PreviewManager","operation":"captureAutomationSnapshot","result":"Failure","target":"thread_preview_tab_A","error":"UnknownVizError"}
{"recordType":"event","offsetMs":3732905.054,"durationMs":10.752375,"component":"PreviewManager","operation":"captureAutomationSnapshot","result":"Failure","target":"thread_preview_tab_A","error":"UnknownVizError"}
{"recordType":"event","offsetMs":3750119.288,"durationMs":15.184084,"component":"PreviewManager","operation":"captureAutomationSnapshot","result":"Failure","target":"thread_preview_tab_A","error":"UnknownVizError"}

Full unsanitized local logs are not attached because they may contain private workspace information.

Workaround

After returning to the thread:

  1. Stop retrying the affected tab after an UnknownVizError or snapshot timeout.
  2. Create a fresh preview tab instead of reusing the old one.
  3. Keep the thread visible while performing snapshot- or click-dependent browser work.
Related issues
  • #3713 — preview_snapshot can fail or time out on loaded pages and leave tab automation unusable
  • #3717 — preview_click returns success in hidden tabs but does not dispatch the click
  • #3718 — preview_open(show: true) can load a tab without showing it to the user
  • #5540 — Embedded browser tabs are not restored after quitting or crashing the app

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in apps/desktop by tracing the PreviewManager detachControlSession and detachListeners calls triggered when switching threads, then reproduce the failure with preview_status or preview_snapshot. Compare the preview lifecycle before leaving and after returning to the thread. Done means returning to a thread preserves automation, reattaches it automatically, or produces a clear recoverable error instead of UnknownVizError or prolonged pending operations.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.