[Bug]: Server browser forgets reported browser profiles on restart, so agents lose logins until a client reconnects#19805

opened18d agobyJJustYannicc

Before submitting

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

Area

apps/server

Reproduction status

This was found by source review and reproduced with a focused server test. The earlier web-client instructions were invalid: Settings disables profile creation outside the desktop app. Work was a proposed fixture name, not a captured real-app setup. Those instructions have been removed.

At main 6318bfc597, the profile settings are disabled when isElectron is false. A paired web client cannot complete the original profile-creation step.

The desktop/client flow remains unverified. It still needs a valid desktop setup that reports a named profile to the server, followed by raw preview_open and preview_status results before and after restarting, with the post-restart calls made before any client reconnects. No verified replacement app steps or raw results are available yet.

The focused service regression and the real-Chromium cookie demo are linked in the candidate comment. The service test models restart before a new client report; the cookie demo checks browser-process recreation. Neither establishes the full app/client restart flow.

Expected behavior

After the restart, the agent's preview_open resolves Work the same way it did before the restart. The tab opens in Work's storage under userdata/server-browser/profiles/<id>, so document.cookie contains t3repro=1 (or the site is signed in). preview_status lists Work in profiles, its defaultProfileId is the client's default, and the tab's entry in tabs has Work's profileId.

Focused-test behavior and source-derived consequences

These are service-test results and source-derived expectations, not captured app/client results. Until a web or desktop client reports again, the server only knows the built-in profiles:

  • preview_open with profileId Work fails with No browser profile is named "Work". Use one of: Default (id default), Incognito (id incognito).
  • preview_status returns profiles with only Default and Incognito, and no defaultProfileId.
  • With no profileId and Work as the reported default, preview_open succeeds, but the tab gets throwaway isolated storage instead of Work. document.cookie has no t3repro (or the site is signed out), and the tab's entry in preview_status tabs has no profileId.

Work's storage is still on disk under userdata/server-browser/profiles/<id>. The server just doesn't know that the id exists.

Cause: apps/server/src/preview/ServerBrowser.ts (main @ 339179f50a). reportedProfiles (line 1349) is only held in memory, and reportProfiles (line 1354) is the only thing that sets it. After a restart it is null:

  • resolveOpenProfile (line 1377) checks a requested id or name against BUILT_IN_BROWSER_PROFILES only.
  • When no profile is requested, it returns undefined.
  • createTab (line 761) gives an agent tab without a profile an isolated context.

The profile storage itself (profilesDir, line 510) does survive restarts.

Relation to #19279: that issue is a separate failure with the same in-memory catalog. There, a second client's report replaces the first client's catalog (last client wins). Here, a restart empties the catalog before any client reports. Fixing #19279 with merge semantics won't fix this, because a merged in-memory catalog is still empty after a restart. For the same reason, persistence shouldn't decide replace-vs-merge. It should save whatever catalog the server currently holds, so it works with whatever semantics #19279 settles on, including that issue's point that omitting a profile shouldn't count as deleting it.

A fix branch exists: https://github.com/JustYannicc/t3code/tree/fix/server-browser-profiles-survive-restart. It saves the server's current catalog atomically to server-browser/reported-profiles.json beside the profile storage, only when it changes, and loads it at startup. It has focused tests. I'll open a PR only if you want one after triage.

Impact

Major degradation or frequent failure

(Every restart breaks agent browsing in signed-in profiles until a web or desktop client connects. Scheduled tasks and phone-only use run into this every time.)

Version or commit

main @ 339179f50a84dc599cce373dbb48f172f182f44e

Environment

Any OS. It's server-side and doesn't depend on the provider. Found by reading the source and reproduced with a focused server test (below). The full app/client flow has not been run; the earlier web-client steps were invalid and have been removed.

Logs or stack traces

shell
1# The new restart test, run against main without the fix:
2# a client reports Work and Personal, the server restarts, and an agent opens with profileId "profile-personal".
3FAIL src/preview/ServerBrowser.test.ts > an agent tab opens in a reported profile after a restart, before any client reports
4PreviewAutomationExecutionError: Preview automation open failed: No browser profile is named "profile-personal". Use one of: Default (id default), Incognito (id incognito).
5Serialized Error: { _tag: 'PreviewAutomationUnknownProfileError' }

Source-derived workaround, not verified end to end

After a restart, open the web or desktop client once before any agent uses the browser, so it reports the profiles again.

Written by Claude Opus 5.5 (Claude Code) on behalf of @JustYannicc.

Synced from GitHub

Candidate for triage: branch at d8b230a.

ServerBrowser now saves its resolved profile catalog and default to server-browser/reported-profiles.json, loads it at startup, validates it, writes atomically only when the catalog changes, and falls back to built-in profiles if saved state is unreadable. Saves serialize concurrent reports and persist the server's current catalog, keeping persistence separate from report-combination policy.

Verification on this commit:

  • ServerBrowser.test.ts and ServerBrowserStream.test.ts: 49 tests passed, including restart-before-report, unchanged-write, and corrupt-file fallback.
  • The opt-in real-Chromium demo retained a persistent cookie across browser-process recreation in an isolated temporary profile. Run it from the checkout with T3_RUN_SERVER_BROWSER_PROFILE_DEMO=1 ./node_modules/.bin/vp test run apps/server/src/preview/ServerBrowserProfiles.demo.test.ts --maxWorkers=2.
  • vp run --filter t3 typecheck, changed-file vp lint, and git diff --check passed.

The manual app/client flow with preview_open before any client reconnect has not been run. #19279 remains open with no fix in flight. I am keeping this as a proposal first, following CONTRIBUTING's guidance to discuss non-trivial changes before a PR.

Synced from GitHub

You're right: the web-client profile-creation steps were invalid. I've corrected the issue body. Work was a proposed fixture name; I have no captured desktop setup or raw before/after preview_open and preview_status results.

The 49 service tests and isolated Chromium cookie demo remain the available evidence. They do not verify the app/client restart flow. The proposal stays open pending a valid desktop reproduction and review of the catalog ownership behavior in #19279.