openai / openai/codex

[macOS][26.831] Browser sidebar owner sync expands 8 durable pages into 84 persisted routes and 76 new renderers

Open
#42,595 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app browser bug performance
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

[macOS][26.831] Browser sidebar owner sync expands 8 durable pages into 84 persisted routes and 76 new renderers

Version

  • ChatGPT desktop / Codex: 26.831.20005 (build 7524)
  • macOS: 26.6.1 (25G76), Apple Silicon
  • Memory: 24 GB

The app has since updated to 26.901.20858 (build 7658), but I have not deliberately stress-reproduced the failure on that build because doing so can make the whole machine unresponsive and interrupt active tasks.

Summary

Opening/rebinding one task with persisted in-app Browser state caused one browser-sidebar owner-sync event to restore 76 duplicate routes in two batches. The checkpoint then contained 84 browser routes even though the canonical page store contained only eight exact owners for that task.

This is not just renderer retention after Browser activity. The restoration path appears non-idempotent: it creates fresh route, tab, and browser-storage IDs for pages already represented in persistent state. ID-only de-duplication cannot recognize those logical duplicates, and the newly generated routes are checkpointed, so killing renderer processes does not repair the cause.

The result was dozens of Codex (Renderer) processes, sustained multi-core CPU load, severe memory pressure, approximately 10 GB of swap, and an almost unusable macOS session.

Exact observed sequence

Affected task and URLs are redacted; counts and timestamps are preserved.

  1. At 2026-09-03T16:47:21.171Z, the desktop log recorded IAB_LIFECYCLE received browser sidebar owner sync for the task.
  2. At 16:47:25Z, 27 unique non-Browser-use tabs were logged as opened.
  3. At 16:47:30Z, another 49 unique non-Browser-use tabs were logged as opened.
  4. The final lifecycle record reported 87 app browser tabs, zero Browser-use tabs, and 84 tabs owned by this task.
  5. The persisted route checkpoint contained:
    • 84 browser routes
    • 84 unique route IDs
    • 84 unique tab IDs
    • 84 unique browser-storage IDs
    • only three distinct restore URLs, with frequency histogram [16, 31, 37]
  6. The canonical browser page store contained only eight exact (conversation, tab, storage-owner) matches for the task, with URL histogram [1, 1, 6].
  7. The 76 tab IDs created in the two restoration batches exactly equaled the 76 checkpoint routes without an exact durable owner match. The symmetric set difference was zero.

Resource impact

The user had already force-quit some renderer children before capture, so these figures are lower bounds for process count:

  • 18 visible renderer processes after partial manual cleanup
  • displayed renderer CPU values totaling approximately 688%
  • displayed per-renderer memory values totaling approximately 21.3 GB
  • macOS memory used: 20.93 GB
  • compressed memory: 11.65 GB
  • swap used: 9.91 GB
  • one sampled renderer: approximately 2.0 GB physical footprint, executing V8 serialization/deserialization work

Controlled recovery / A-B result

With the app fully stopped, I removed only the 76 routes lacking an exact durable owner match, using the pre-quit canonical page store as the ownership authority. I preserved all eight exact owner matches and did not change the canonical page store.

  • before: 84 routes, three restore URLs, histogram [16, 31, 37]
  • after: 8 exact durable routes, histogram [1, 1, 6]
  • dropped: 76 orphan routes
  • writes were atomic, backed up, JSON-validated, and verified after write

After a clean launch, the app stabilized at four renderer processes and approximately 1.6-2.0 GB aggregate renderer RSS. Aggregate renderer CPU generally returned to low single digits after startup when idle.

This recovery is more durable than killing individual renderers, because the bad checkpoint otherwise remains available for rehydration.

Why the current limits do not contain it

Inspection of the packaged client indicates that restored routes are de-duplicated by tab ID. In this failure, every duplicate receives a fresh tab ID, so that comparison cannot collapse them.

The detached-page budget also appears non-atomic with batch restoration: enforcement can skip pages while restoration or suspension is pending, and eviction is selected one item at a time. A restoration batch can therefore create dozens of webviews before the budget converges, if it converges at all.

Expected behavior

  • Browser route restoration should be idempotent across owner-sync/rebind events.
  • Restored routes should be reconciled against canonical page ownership or a stable logical page identity, not only fresh tab IDs.
  • Checkpoint routes whose durable page records no longer exist should be pruned or quarantined.
  • A renderer/page budget should be reserved before a restoration batch creates webviews.
  • Under CPU or memory pressure, the app should stop restoration and reopen the task in a safe state rather than exhausting the machine.

Suggested regression test

  1. Persist a task with eight Browser pages across three restore URLs.
  2. Trigger repeated owner-sync/rebind and app relaunch cycles.
  3. Assert that route count, unique logical pages, live webviews, and renderer count remain bounded.
  4. Evict some canonical page records while leaving route checkpoints, then repeat restoration.
  5. Assert that stale routes are pruned and that the restoration batch cannot exceed the page/renderer budget.

Related reports

  • #35083 documents in-app Browser hosts/renderers retained after session activity ends.
  • #38751 documents eager restoration of every persisted in-app Browser tab and the resulting memory pressure.
  • #39552 documents a persisted in-app Browser tab that rehangs a task on restore.
  • #32663 documents webview/renderer multiplication when a task is reopened.

This report adds a separate, exact creation mechanism: one owner-sync generated 76 fresh IDs, and those 76 IDs exactly matched the 76 newly orphaned persisted routes.

Diagnostics available privately

I can provide the following through a secure support channel:

  • sanitized lifecycle excerpt covering the owner-sync and both restoration batches
  • before/after route ownership manifests
  • sample and vmmap output for an affected renderer
  • process snapshots and Activity Monitor screenshots
  • hashes for the complete local logs and state files

Raw desktop logs and persisted Browser state are not attached publicly because they contain private task text, local paths, and authenticated browsing data.

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 with the browser sidebar owner-sync and route restoration paths described in the report; no source files or existing tests are named. Reproduce repeated owner-sync/rebind and relaunch cycles with eight pages, then test stale-route pruning and restoration limits. Done means logical pages, routes, webviews, and renderer processes remain bounded without exhausting system resources.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, rust
Domain
desktop, performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.