Summary
On a clean install of Buzz Desktop 0.5.14, the window opens and stays blank white indefinitely (observed >1 hour). The Rust side starts fine and writes its state files; the WebView is created, the custom scheme handlers are registered, and the load of tauri://localhost/index.html is started — but the app's WKNavigationDelegate never calls its decision handler for that navigation. The navigation sits pending forever. When the process is killed, the pending listener finally fires with policyAction=Ignore.
So the app is not crashing or hanging: it silently refuses to load its own frontend.
Environment
|
|
| Buzz |
0.5.14 (CFBundleVersion 0.5.14, CFBundleShortVersionString 0.5.14) |
| Bundle |
xyz.block.buzz.app, /Applications/Buzz.app, built 2026-08-15 05:02 |
| OS |
macOS 26.6 (25G72) |
| Arch |
arm64 (Apple silicon) |
| Install |
fresh, from the official DMG |
| Signature |
Developer ID Application: Block, Inc. (EYF346PHUG), notarization ticket stapled, spctl -a -t exec → accepted, no quarantine xattr |
Steps to reproduce
- Install Buzz Desktop 0.5.14 from the DMG on macOS 26.6 (arm64).
- Launch the app.
- Window appears, blank white, and never renders the UI.
Reproduced on 3 consecutive cold launches (PIDs 51572, 51676, 51795). Deleting ~/Library/Application Support/xyz.block.buzz.app and reinstalling does not help — the directory is recreated and the behaviour is identical.
Root cause evidence
1. The navigation is started but never decided
From the unified log, launch at 16:10:27 (PID 51676 / WebContent 51680):
.736 WebPage::registerURLSchemeHandler: Registered handler 2 for the '<private>' scheme
.736 WebPage::registerURLSchemeHandler: Registered handler 3 for the '<private>' scheme
.736 WebPage::registerURLSchemeHandler: Registered handler 1 for the '<private>' scheme
.736 WebPage::registerURLSchemeHandler: Registered handler 10 for the '<private>' scheme
.740 WebPage::loadRequest: navigationID=28, shouldTreatAsContinuingLoad=0, lastNavigationWasAppInitiated=1
.740 FrameLoader::loadWithDocumentLoader: main frame load started
.743 WebPageProxy::decidePolicyForNavigationAction: frameID=4294967297, isMainFrame=1, navigationID=28
.745 beginSafeBrowsingCheck: no threat, completing navigationID=28
<nothing further for navigationID=28 — no receivedNavigationActionPolicyDecision,
no didCommitLoad, no didFailProvisionalLoad — for the remaining 25 s of capture>
WebKit only continues a navigation once both the Safe Browsing check has finished and the embedder's navigation delegate has invoked its decision handler. Safe Browsing completed in 2 ms. The delegate never answered.
2. The pending decision resolves as Ignore when the process is torn down
When PID 51676 was killed (16:15:20), the held listener fired at last:
16:15:20.093 WebPageProxy::decidePolicyForNavigationAction: listener called:
frameID=4294967297, isMainFrame=1, navigationID=28,
policyAction=Ignore, isAppBoundDomain=0, wasNavigationIntercepted=0
16:15:20.093 WebPageProxy::receivedNavigationActionPolicyDecision:
frameID=4294967297, isMainFrame=1, navigationID=28, policyAction=Ignore
policyAction=Ignore is the app's own answer — i.e. Buzz's navigation policy path decides to cancel the load of its own index.html, and only surfaces that decision at shutdown. This looks like an on_navigation / capability-scope gate that is waiting on some condition that is never satisfied, and whose fallback is "deny".
3. What the white pixels actually are
.735 DocumentLoader::startLoadingMainResource: Returning empty document
.735 FrameLoader::setState: main frame load completed
.841 RemoteLayerTreeDrawingAreaProxy(24) Unhiding layer tree
The visible window is the initial empty document that precedes navigation 28. Since navigation 28 never commits, that empty document is what the user looks at forever.
4. The main thread is not blocked
sample of buzz-desktop, 5 s, 3765 samples — the main thread is idle in the normal AppKit run loop for 100% of them:
3765 Thread_... DispatchQueue_1: com.apple.main-thread
3765 buzz_lib::run
3765 tauri::app::App<R>::run
3765 tao::platform_impl::platform::event_loop::EventLoop<T>::run
3765 -[NSApplication run]
... _DPSNextEvent -> mach_msg2_trap
So this is not a deadlock on the main thread — the decision handler is simply never invoked (or is dropped) on a path that later defaults to Ignore.
5. Target URL confirmed
strings on the binary shows tauri://localhost + index.html, and Contents/Resources/ contains only icon.icns — the frontend is embedded and served over the custom scheme, so no network dependency is involved.
Ruled out
-
Crash — zero entries for Buzz in ~/Library/Logs/DiagnosticReports.
-
Gatekeeper / quarantine / signature — see Environment above; all clean.
-
Stale window or app state — ~/Library/Saved Application State/xyz.block.buzz.app.savedState does not exist; no xyz.block.buzz.app preferences domain (defaults read → "domain does not exist"); .window-state.json is sane (1600×1200 at 0,60, visible: true, maximized: true); wiping Application Support changes nothing.
-
Missing frontend assets — embedded in the binary, and the scheme handlers register successfully.
-
Keychain / SecretStore (initially suspected, then excluded) — an early sample caught a tokio worker in managed_agents::storage::load_managed_agents → SecretStore::load → SecretStore::migrate_legacy_key → migrate_legacy_key_keyring → keyring::Entry::get_password → SecKeychainFindGenericPassword, i.e. the legacy CSSM keychain path. It looked like a plausible blocker, but it is not the cause: samples at t+20 s, t+80 s and t+140 s after launch show no SecretStore frames at all, a single lookup against login.keychain-db (9.3 MB, 2960 generic items) takes 15 ms, and securityd produced only 20 log lines for the process over 3 minutes. The navigation is still un-decided long after that work has finished.
Worth noting separately though: migrate_legacy_key_keyring goes through SecKeychainFindGenericPassword, the deprecated file-keychain API, which is slow and can prompt; on this machine only one buzz-desktop service entry exists in the login keychain.
Questions for maintainers
- Under what conditions does Buzz's navigation policy path return
Ignore for tauri://localhost/index.html? Is there an on_navigation handler or a capability/scope check gating the first load on some initialization state?
- Is there a path where the decision handler is captured into an async task that can never resolve (leaving the navigation pending until teardown)?
- Is there a way to get diagnostics out of a release build without a debug console? The app writes no log file of its own (
~/Library/Logs/Buzz does not exist), which made this considerably harder to pin down than it needed to be.
Attachments
buzz-report2-sanitized.txt — bundle metadata, code signature, full sample of buzz-desktop, process tree, state directory inventory.
buzz-report3-sanitized.txt — keychain measurements, three timed stack samples, and the WebKit navigation trace including the policyAction=Ignore lines.
Paths and local addresses in the attachments have been redacted.
buzz-report2-sanitized.txt
buzz-report3-sanitized.txt
Summary
On a clean install of Buzz Desktop 0.5.14, the window opens and stays blank white indefinitely (observed >1 hour). The Rust side starts fine and writes its state files; the WebView is created, the custom scheme handlers are registered, and the load of
tauri://localhost/index.htmlis started — but the app'sWKNavigationDelegatenever calls its decision handler for that navigation. The navigation sits pending forever. When the process is killed, the pending listener finally fires withpolicyAction=Ignore.So the app is not crashing or hanging: it silently refuses to load its own frontend.
Environment
CFBundleVersion0.5.14,CFBundleShortVersionString0.5.14)xyz.block.buzz.app,/Applications/Buzz.app, built 2026-08-15 05:02Developer ID Application: Block, Inc. (EYF346PHUG), notarization ticket stapled,spctl -a -t exec→ accepted, no quarantine xattrSteps to reproduce
Reproduced on 3 consecutive cold launches (PIDs 51572, 51676, 51795). Deleting
~/Library/Application Support/xyz.block.buzz.appand reinstalling does not help — the directory is recreated and the behaviour is identical.Root cause evidence
1. The navigation is started but never decided
From the unified log, launch at 16:10:27 (PID 51676 / WebContent 51680):
WebKit only continues a navigation once both the Safe Browsing check has finished and the embedder's navigation delegate has invoked its decision handler. Safe Browsing completed in 2 ms. The delegate never answered.
2. The pending decision resolves as
Ignorewhen the process is torn downWhen PID 51676 was killed (16:15:20), the held listener fired at last:
policyAction=Ignoreis the app's own answer — i.e. Buzz's navigation policy path decides to cancel the load of its ownindex.html, and only surfaces that decision at shutdown. This looks like anon_navigation/ capability-scope gate that is waiting on some condition that is never satisfied, and whose fallback is "deny".3. What the white pixels actually are
The visible window is the initial empty document that precedes navigation 28. Since navigation 28 never commits, that empty document is what the user looks at forever.
4. The main thread is not blocked
sampleofbuzz-desktop, 5 s, 3765 samples — the main thread is idle in the normal AppKit run loop for 100% of them:So this is not a deadlock on the main thread — the decision handler is simply never invoked (or is dropped) on a path that later defaults to
Ignore.5. Target URL confirmed
stringson the binary showstauri://localhost+index.html, andContents/Resources/contains onlyicon.icns— the frontend is embedded and served over the custom scheme, so no network dependency is involved.Ruled out
Crash — zero entries for Buzz in
~/Library/Logs/DiagnosticReports.Gatekeeper / quarantine / signature — see Environment above; all clean.
Stale window or app state —
~/Library/Saved Application State/xyz.block.buzz.app.savedStatedoes not exist; noxyz.block.buzz.apppreferences domain (defaults read→ "domain does not exist");.window-state.jsonis sane (1600×1200 at 0,60,visible: true,maximized: true); wiping Application Support changes nothing.Missing frontend assets — embedded in the binary, and the scheme handlers register successfully.
Keychain /
SecretStore(initially suspected, then excluded) — an early sample caught a tokio worker inmanaged_agents::storage::load_managed_agents → SecretStore::load → SecretStore::migrate_legacy_key → migrate_legacy_key_keyring → keyring::Entry::get_password → SecKeychainFindGenericPassword, i.e. the legacy CSSM keychain path. It looked like a plausible blocker, but it is not the cause: samples at t+20 s, t+80 s and t+140 s after launch show noSecretStoreframes at all, a single lookup againstlogin.keychain-db(9.3 MB, 2960 generic items) takes 15 ms, andsecuritydproduced only 20 log lines for the process over 3 minutes. The navigation is still un-decided long after that work has finished.Worth noting separately though:
migrate_legacy_key_keyringgoes throughSecKeychainFindGenericPassword, the deprecated file-keychain API, which is slow and can prompt; on this machine only onebuzz-desktopservice entry exists in the login keychain.Questions for maintainers
Ignorefortauri://localhost/index.html? Is there anon_navigationhandler or a capability/scope check gating the first load on some initialization state?~/Library/Logs/Buzzdoes not exist), which made this considerably harder to pin down than it needed to be.Attachments
buzz-report2-sanitized.txt— bundle metadata, code signature, fullsampleofbuzz-desktop, process tree, state directory inventory.buzz-report3-sanitized.txt— keychain measurements, three timed stack samples, and the WebKit navigation trace including thepolicyAction=Ignorelines.Paths and local addresses in the attachments have been redacted.
buzz-report2-sanitized.txt
buzz-report3-sanitized.txt