Skip to content

Fix browser panes rendering blank after reopen - #2141

Merged
austinywang merged 1 commit into
mainfrom
issue-2137-browser-blank-after-reopen
Mar 25, 2026
Merged

austinywang merged 1 commit into
mainfrom
issue-2137-browser-blank-after-reopen

Conversation

@austinywang

@austinywang austinywang commented Mar 25, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2137

Summary

  • restore browser session state through an explicit session-restore path instead of constructor-time initial URL loading
  • preserve restored current URL even when there is no back/forward history
  • make browser refresh fall back to the restored/current URL when WKWebView has no live URL

Testing

  • built and launched with ./scripts/reload.sh --tag browser-blank-fix --launch
  • local tests not run per repo policy

Summary by cubic

Fixes #2137 by restoring browser panes via an explicit session-restore path. Reload now falls back to the restored URL to avoid blank pages after reopen.

  • Bug Fixes
    • Added a restoreSessionSnapshot path that restores history, current URL, and shouldRenderWebView, then navigates without constructor-time URL loading.
    • During session restore, create the browser with url: nil to prevent premature loads; apply page zoom and devtools state after restoration.
    • Preserve and use the restored current URL even with empty history; on reload, if WKWebView has no live URL, navigate to the resolved current or last attempted URL.

Written for commit 0b891ff. Summary will update on new commits.

@vercel

vercel Bot commented Mar 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 25, 2026 11:08am

@austinywang
austinywang merged commit 049d296 into main Mar 25, 2026
14 checks passed
@austinywang
austinywang deleted the issue-2137-browser-blank-after-reopen branch March 25, 2026 11:11
@greptile-apps

greptile-apps Bot commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes blank browser panes after session reopen by decoupling construction-time URL loading from session restoration and introducing a unified restoreSessionSnapshot path that ensures navigation history is set up before the first page load.

Key changes:

  • newBrowserSurface is now called with url: nil; the URL is loaded inside restoreSessionSnapshot after history is already in place, eliminating the root cause of the blank pane
  • restoreSessionNavigationHistory now also activates the restored-history overlay when there is a current URL but no back/forward stack, preserving the current URL across reopens that previously fell through the guard
  • reload() gains a fallback that navigates to resolvedCurrentSessionHistoryURL() (or lastAttemptedURL) when webView.url is blank, recovering from cases where the WKWebView process hasn't loaded a live URL yet
  • The zoom factor is still applied before restoreSessionSnapshot in applySessionPanelMetadata, preserving the previous ordering guarantee

Confidence Score: 4/5

  • This PR is safe to merge; the logic is sound and the fix is well-scoped to the session-restore path.
  • The root-cause analysis is correct and the three-part fix (deferred URL loading, widened history guard, reload fallback) works together cleanly. The only subtle edge case — shouldRenderWebView = true with an unsanitizable urlString — is theoretically possible but cannot arise from the serialization code, and the worst outcome is a blank WebView rather than a crash. Manual testing was performed per repo policy ("local tests not run per repo policy"). Giving 4 rather than 5 because the change touches WebView lifecycle ordering, which is historically delicate.
  • Sources/Panels/BrowserPanel.swift — specifically the early-return branch in restoreSessionSnapshot when shouldRenderWebView is true but restoredURL is nil.

Important Files Changed

Filename Overview
Sources/Panels/BrowserPanel.swift Adds restoreSessionSnapshot to consolidate URL navigation + history restore, widens the guard in restoreSessionNavigationHistory to also fire when only a current URL is present, and adds a fallback navigation path in reload() when webView.url is nil/blank.
Sources/Workspace.swift Switches browser surface construction to url: nil and replaces the old split restoreSessionNavigationHistory call with the new unified restoreSessionSnapshot, ensuring zoom is still applied before the restore path.

Sequence Diagram

sequenceDiagram
    participant WS as Workspace
    participant BP as BrowserPanel
    participant WV as WKWebView

    Note over WS,WV: Session Restore (new flow)
    WS->>BP: newBrowserSurface(url: nil)
    BP->>WV: makeWebView() – no initial navigation
    WS->>BP: setPageZoomFactor(zoom)
    WS->>BP: restoreSessionSnapshot(snapshot)
    BP->>BP: restoreSessionNavigationHistory(back, fwd, currentURL)
    BP->>BP: set usesRestoredSessionHistory, restoredHistoryCurrentURL
    BP->>BP: currentURL = restoredURL
    BP->>BP: shouldRenderWebView = true
    BP->>WV: navigateWithoutInsecureHTTPPrompt(restoredURL, preserveHistory: true)
    WV-->>BP: url KVO → currentURL updated

    Note over WS,WV: Reload fallback (new)
    WS->>BP: reload()
    BP->>WV: webView.url?
    WV-->>BP: nil / blank
    BP->>BP: resolvedCurrentSessionHistoryURL() → fallbackURL
    alt fallbackURL is valid
        BP->>WV: navigateWithoutInsecureHTTPPrompt(fallbackURL)
    else no fallback
        BP->>WV: webView.reload()
    end
Loading

Reviews (1): Last reviewed commit: "Fix browser pane restore after reopen" | Re-trigger Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Comment on lines +3010 to +3016
currentURL = snapshot.shouldRenderWebView ? restoredURL : nil
shouldRenderWebView = snapshot.shouldRenderWebView

guard snapshot.shouldRenderWebView, let restoredURL else {
refreshNavigationAvailability()
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Blank WebView when shouldRenderWebView is true but URL is unsanitizable

If snapshot.shouldRenderWebView is true but Self.sanitizedSessionHistoryURL(snapshot.urlString) returns nil (e.g. corrupt/missing URL in persisted data), the code sets shouldRenderWebView = true and currentURL = nil, then takes the early-return branch. The WebView will be rendered but completely blank rather than falling back to the new-tab/empty state.

The old code would have called newBrowserSurface(url: nil), leaving shouldRenderWebView = false (no navigation triggered), so the user would have seen a clean new-tab page instead.

In practice this can't happen with a valid session file because shouldRenderWebView is serialised from browserPanel.shouldRenderWebView, which is only set to true alongside a real navigation. But it's worth guarding explicitly so corrupt sessions degrade gracefully:

currentURL = (snapshot.shouldRenderWebView && restoredURL != nil) ? restoredURL : nil
shouldRenderWebView = snapshot.shouldRenderWebView && restoredURL != nil

Jesssullivan added a commit to Jesssullivan/cmux that referenced this pull request Mar 26, 2026
Ingests all upstream fixes since 2026-03-22 including:
- Fix Cmd+N crash: retain snapshot workspaces (manaflow-ai#2183, manaflow-ai#2181, manaflow-ai#2178, manaflow-ai#2173)
- Fix browser pane restore after reopen (manaflow-ai#2141)
- Fix Ghostty resize_split keybind (manaflow-ai#1899)
- Reduce shell integration prompt latency (manaflow-ai#2109)
- Fix command palette focus after terminal find (manaflow-ai#2089)
- Add Codex CLI hooks (manaflow-ai#2103)
- Add cmux.json custom commands (manaflow-ai#2011)
- Fix window position restore on relaunch (manaflow-ai#2129)

Conflict resolution:
- BrowserPanel.swift: accepted upstream configureWebViewConfiguration()
  refactor (already includes our forMainFrameOnly:true CAPTCHA fix from PR manaflow-ai#1877)

Fork-specific files preserved:
- Sources/Panels/WebAuthn{Coordinator,BridgeJavaScript}.swift
- Sources/FIDO2/module.modulemap
- vendor/ctap2 submodule
- cmux.entitlements (with camera/audio-input removed)
- cmux.embedded.entitlements
- .github/workflows/fork-{ci,release}.yml
bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026

This branch was successfully deployed

1 active deployment
Preview — 0b891ffb Deployed Mar 25, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Browser panes render blank after quit and reopen, refresh doesn't fix

1 participant