Skip to content

Closing and reopening a split thread can trigger React #185 #1250

Description

@ratulsarna

Summary

After the first split-thread open succeeds, closing the right pane and opening that thread in split again can trigger React error #185 and blank the entire app.

This was discovered while QAing #1246 and its fix in #1249. It is a separate failure: the repeating stack does not enter FollowUpPromptBox.

Version

Reproduction

  1. Open a thread in a single pane.
  2. From a sidebar thread's actions, choose Open in split.
  3. Close the right pane.
  4. Open the same sidebar thread in split again.

Expected

The split reopens with both threads rendered.

Actual

The second split open blanks the route and logs minified React error #185 (maximum update depth exceeded).

Evidence

The failing stack maps to:

usePaneSecondaryPanelRegistration layout effect
  -> registration.publish(model)
  -> createPaneSecondaryPanelRegistry.publish
  -> notify(paneId)
  -> focused-pane useSyncExternalStore listener
  -> React #185

On the second open, the instrumented build produced 52 fresh model publications for each pane before React stopped the loop. The focused pane had one active listener; the other pane had none. Observable panel fields stayed unchanged, but the hosted panel and model references were new on every pass.

At least three independent identity paths recreate the hosted model:

  • a render-created environment open context changes openPathInFileTarget, then renderHostedPanel
  • useThreadStorageBrowser returns a fresh controller object, recreating metadata content
  • the secondary-panel fileTabs array is recreated for the reopened thread

The resulting cycle is:

fresh owner values
  -> fresh hosted panel model
  -> layout-effect publish
  -> registry synchronously notifies focused host
  -> host renders the panel
  -> pane renders again
  -> fresh owner values

Suppressing that registry notification moved #185 to a Radix Popper ResizeObserver setter during the same repeat transition. The registry loop is proven, but fixing only its first unstable reference may reveal another mount-time writer.

Fix direction

Avoid publishing an opaque ReactNode from a child layout effect into a synchronously subscribed ancestor. The registry should carry semantic layout state, while panel content remains React-owned through a stable host/slot boundary.

A fix should preserve panel focus, live content updates, resize behavior, and composer context without relying on memoizing every current callback or object producer.

Acceptance criteria

  • Open split -> close pane -> reopen split keeps both panes rendered.
  • No React Surface active pull request status #185 or blank route.
  • Registry publication/notification remains bounded.
  • Hosted panel content still updates correctly.
  • A regression test exercises the full open -> close -> reopen transition.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions