Repository navigation
iPhone Connect caches truncated startup JavaScript, causing persistent blank screen; native recovery hits 401 #3791
Description
Summary
A user lost access to BB on their iPhone: both the existing Safari tab at https://brsbl.getbb.app/ and the native BB app showed a persistent black/blank screen. A fresh Private-browser tab worked after sign-in, providing a workaround. Clearing website data and signing in again did not restore the native app; recovery attempts also produced HTTP 401, and the user separately reported HTTP 503 screens.
Inspection of the affected Safari tab confirmed that it repeatedly loaded a truncated cached startup JavaScript file, which failed to parse before the app could render. Fetching the complete file and reloading restored app mounting, including on a subsequent normal reload. The native app remained blank until the user deleted and reinstalled it, which they confirmed restored access.
The Safari blank-screen mechanism is established, but why the file became truncated and cacheable remains unknown. The native app's failing state was not captured, so neither the same corruption nor an authentication problem is established as its cause. Access is recovered; preventing recurrence and making recovery reliable remain open.
Versions and environment
- Incident reported September 16, 2026, approximately 13:12–13:30 America/New_York; affected phone inspected at approximately 14:42–14:45.
- Phone: iOS 26.6.1, confirmed by Safari’s device inspector. Affected browser: regular iPhone Safari tab. Phone model and native BB app build remain unknown.
- Host BB CLI:
0.43.2-nightly.34866755923.1, packaged Nightly on macOS 26.5.2 (25F84). Inspecting Mac Safari: 26.5.2. The successful nightly publication run maps this host version to commitd89160eb8c69c1e3ebc2ba2514f1711af8d7c506(September 14). This is host build provenance, not the unknown native app build. - Latest successful repository-recorded Connect deployment before the incident: September 12, commit
3b37d2790d084a47c96eb78267da5d159598f203, Worker version27889535-f8a2-413d-9868-6ace3330b64c. Deployment logs establish this record; out-of-band deployments cannot be excluded without Cloudflare access. - Connect server:
https://brsbl.getbb.app/. - Source inspected:
e6c615b87056ed2a3aedd46b4c01064f6fa132a9; latest comparison with fetchedorigin/mainatc024ceac524882b7bf9fbef41c14c4911919de4c. Relevant relay/cache/session code and static asset serving logic are unchanged. The deployed-gate record has the same inspected relay/cache/encoding code; the reported host nightly has the same inspected host static-serving and tunnel-client code. This is source comparison, not a reproduction of the initiating failure on main. Native source has evolved since the host nightly and must not be used to infer the installed phone version.
Steps to reproduce
Confirmed browser failure and recovery
This reproduces the reporter’s existing damaged cache, not a deterministic way to create it from a clean installation.
- Open the existing regular Safari tab at
https://brsbl.getbb.app/on the affected iPhone. The page is black/blank. Adding a query string to the document URL does not recover it. - Attach Mac Safari Web Inspector to that iPhone tab and reload normally.
- Observe an empty
#root, the startup script loaded from memory cache, and the syntax error below. - Export the network trace locally and compare the cached startup response with fresh responses for
/assets/index-BaDU-L7_.js(exact URL and a cache-busted URL withcache: no-store). The cached body is an exact prefix of both complete responses. - After fetching the complete responses and reloading, observe populated app DOM and resumed application requests. Repeat a normal reload: app mounting succeeds and the startup SyntaxError does not return. The reporter’s visual confirmation has not been obtained.
A fresh Private-browser tab also worked after sign-in. No explicit cookie/site-data deletion or new sign-in was needed during the inspected regular-tab recovery.
Native failure and recovery, reporter-observed
- The native BB app’s saved connection initially shows a blank page.
- Long-press the home-screen BB icon → Device settings → Clear website data. This does not restore access; the reporter subsequently captures HTTP 401.
- Generate a fresh code on the host with
bb connect machine-code. On the phone, use Device settings → Servers → long-press server → Sign in again, then redeem the code. - The code lookup confirms
consumed: true; the reporter still sees the same 401 screen. The phone’s post-pairing cookie installation/transmission is unverified. - After the browser recovery, the reporter confirms the native app is still blank.
- Delete and reinstall the native BB app: the reporter confirms this fixes it. Whether the same build was reinstalled and whether fresh pairing/sign-in was required have not been confirmed. The old native state is no longer available for inspection.
Expected vs actual
Expected: complete startup assets execute and BB loads; failed transfers should not leave a persistently unusable cached app. Native recovery should restore a usable session.
Actual browser console:
SyntaxError: Unexpected end of script
/assets/index-BaDU-L7_.js:26
Native error captured during failed recovery (before the successful reinstall):
The server answered with an error
HTTP 401
Try again
Device settings
HTTP 503 screens were also reported. Their exact timing, client, and response body remain unknown.
Evidence
Confirmed truncated cache entry
| Measurement | Cached startup response | Fresh response |
|---|---|---|
| Decoded body bytes | 832,191 | 1,011,640 |
| SHA-256 | 5fea59a405972cb2f24f7b61da9ee1cb0c9b357493eb5110e4103cec241e2db1 |
85a209186bb8f3d0d1dac1b6d4ae95f2342436dcd0a2d55bf68e39a2d34dbe74 |
The cached body is an exact prefix of the complete file, missing 179,449 bytes, and ends mid-assignment:
...t[61]=se,t[62]=I,t[63]=n,t[64]=
The failing response records HTTP 200 and:
Cache-Control: public, max-age=31536000, immutable
Content-Encoding: br
Vary: Accept-Encoding, Origin
Date: Wed, 16 Sep 2026 00:58:45 GMT
x-bb-cache: miss
cf-ray: a3bbec720a237c96-EWR
Causal mechanism: truncated immutable script cached on the phone → reload reuses it → parsing fails before React mounts → empty black page. Changing the document query leaves the hashed script URL unchanged. Private browsing avoids the damaged cache. Authentication does not explain this reproduced browser failure.
Both fresh phone fetches returned the same complete bytes: the exact-URL fetch arrived with zstd, and the cache-busted fetch with Brotli. This does not establish a compression-specific defect. The startup error happens before React and its error boundary are installed, explaining the lack of an in-app crash panel.
Raw HAR headers were not published because they can contain credentials. The temporary HAR was removed after extracting and verifying the measurements. The malformed bytes remain reproducible from the original complete asset: take its first 832,191 bytes; that prefix reproduces the captured bad SHA-256 exactly. This reconstructs the payload, not the original cache-writing failure.
Healthy origin representations
Fresh HTTP reads of the same asset from the host origin http://127.0.0.1:38886 all completed normally. Each decoded to 1,011,640 bytes and the good SHA-256 above:
| Requested representation | Wire bytes | Origin Content-Length | Decoded hash |
|---|---|---|---|
| Identity | 1,011,640 | 1,011,640 | Good hash above |
| Brotli | 237,668 | 237,668 | Good hash above |
| Gzip | 300,285 | 300,285 | Good hash above |
The host static handler reads the asset into memory and supplies the compressed file length for precompressed responses. These checks rule out a persistently malformed current origin artifact, not a transient failure during the original transfer. The captured failed response headers contained no Content-Length.
Lead for the initiating truncation event
The cached response predates daytime troubleshooting. Host server.69.log shows a tunnel interruption about 68 seconds after its response timestamp:
2026-09-16T00:59:52.831Z tunnel heartbeat missed; reconnecting
2026-09-16T00:59:52.833Z tunnel closed (code 1006); reconnecting in 1000ms
2026-09-16T00:59:54.233Z tunnel connected
The wider 00:53–01:04 UTC host log window also contains missed tunnel heartbeats at 00:53:08.093, 00:54:10.654, and 01:00:54.236. At 00:59:04.922 an npm lookup was aborted; at 00:59:05.534 a host lookup failed with host_unavailable. These support broader instability around the download, without identifying the failing layer. A bounded macOS power-log check found no Sleep/Wake transition in this window; this does not exclude network loss or scheduling stalls.
Heartbeat detection runs every 20 seconds with a 60-second acknowledgment deadline (source). Therefore the logged disconnect time is detection time, not a precise timestamp for the first lost byte.
Use the original response timestamp and ray ID to inspect edge logs. x-bb-cache: miss is a stored response header, not proof that every later delivery bypassed all caches; another Cloudflare cache layer can replay it. Host logs do not record byte counts for this asset request: detailed response-size logging is limited to initial thread-load APIs. Cloudflare request logs/runtime traces were unavailable with the investigation’s credentials.
Transport and cache source audit: leads, not a proven initiating defect
- The host tunnel client sends
body-endafter consuming the origin response; an origin read error goes throughclose-stream. The edge closes normally onbody-end, while disconnect handling requests a stream abort. Source inspection did not prove that a disconnect is intentionally converted into successful EOF. - The edge relay uses an ordinary TransformStream, with no expected-length accounting before accepting
body-end; that protocol message carries no byte count or digest. Cloudflare documents that manually set lengths are ignored for arbitrary streaming bodies. Its FixedLengthStream can enforce exact byte counts. This identifies a potential integrity-check improvement, not proof that its absence caused this incident; compression/transcoding boundaries must be handled correctly. - Asset caching clones and streams cacheable successful responses into
cache.putwhile serving the visitor. No application-level asset checksum is checked. The observed incomplete response nevertheless being reusable is proven; which layer treated it as complete is not. - Do not blindly change the response encoding mode: PR #915 established that the relay/cache-hit paths need manual encoding while the cache-miss path is automatically decoded/re-encoded. Its raw-gzip corruption differs from this exact plaintext-prefix truncation.
- Existing Node-level stream replacement coverage expects a pending body read to reject. Existing workerd encoding tests cover complete compressed bodies and cache hits/misses. Neither demonstrates interrupted, partially delivered compressed assets through edge caching and actual Safari. These tests were read, not run in this diagnosis.
Separate native recovery defect
- Clear website data deletes both cookie stores without awaiting completion or renewing the session. Native session state can remain authenticated after its web cookie is gone.
- The one-hour session remains apparently authenticated after cookie deletion. Foreground renewal checks only renew an authenticated session within five minutes of expiry. The native SDK’s separate machine-credential connection can remain healthy, so its auth recovery need not run.
- Try again only remounts the page. Page HTTP errors do not invoke session verification.
- In installed
react-native-webview@13.16.1, iOSclearCache(true)includes localStorage, sessionStorage and IndexedDB. However, BB unmounts the WebView on the HTTP error screen, so the optional-ref cache clear then does nothing while cookie clearing still runs. The “Cleared” toast acknowledges command delivery, not completed deletion. Earlier troubleshooting advice that this dependency never clears local storage was incorrect. - Direct server requests confirmed: valid cookie → 200; omit cookie → 401; retry without it → 401; restore it → 200. This is direct server evidence plus source tracing, not an independently reproduced native UI sequence. The gate’s 401 sign-in HTML is hidden by BB’s generic native error panel when the WebView is unmounted.
A further startup-detection limitation: native onLoadEnd marks the page ready without proving that the app JavaScript mounted. This can fail to surface a bundle startup error, but the native bundle error was not captured here.
Recommended recovery direction: await data clearing, reinstall a fresh Connect session before reload, and route page-level 401 through session recovery. Cache clearing must also work without a mounted WebView. Fresh pairing changes the connection identity and should already mint/install a cookie, so its reported failure is not explained solely by the reset defect. Still needed: the native page’s failing URL/status and cookie-presence/validation result, without disclosing token values, plus the native app build.
HTTP 503 recovery limitation
Connect emits HTTP 503 when no open host tunnel is available. Its HTML error page refreshes every ten seconds, but the native app replaces main-frame HTTP errors with its generic panel and unmounts the page, preventing that HTML recovery from running. This is a source-level recovery limitation; the reporter’s uncaptured 503 responses cannot yet be attributed to this specific path.
Originating BB thread (owner access required).
What was ruled out / remains open
- Fresh public startup assets were complete; the damaged phone copy differs from them. Earlier healthy host/network checks did not examine that cache.
- The browser blank screen is reproduced and explained. The original event that allowed an incomplete response into cache is not yet established.
- Native cache corruption has not been verified. Reinstalling recovered access; the reasons for its earlier blank screen, failed re-pair recovery, and reported 503s remain unproven. A changed app build or session during reinstall is a possible confound.
- Inspection limitation: after reconnecting/unlocking the iPhone, Mac Safari exposed its Safari tabs but no native BB WebView. Current BB source gates WebView debugging on
__DEV__. The installed app build remains unknown; this explains the expected release-build limitation but does not diagnose its blank screen. macOS Console did not list the phone as an available log source. - Earlier clean source-app checks in Chrome for Testing and desktop Safari did not reproduce the damaged phone state. No native simulator was available.
- bb Connect: a plugin serving a sandboxed document cannot serve that document's own files #3617 concerns sandboxed plugin subresources; this failure is the top-level startup bundle. Mobile Remote Access Template - UI/UX Hidden Due to Responsiveness Issues #1603 concerns older Safari parsing compatibility; here the body is demonstrably truncated.
- No product code changes, PR, deployment, or local tests were made.
Remaining investigation and verification
Available incident evidence, source/history, origin representations, publication/deployment records, and bounded host/power logs have been examined. No production restart, cache purge, configuration change, code change, or deliberate connection interruption was performed.
To establish the initiating defect, the next useful work is:
- With authorized Cloudflare access, correlate ray
a3bbec720a237c96-EWRand the original timestamp with request outcomes, stream errors, cache status and byte counts if those fields were retained. Historical metadata may be insufficient to recover the original cause. - In an isolated environment, interrupt host/tunnel and visitor connections partway through a compressed immutable asset; verify that the response errors and neither edge nor Safari reuses a partial success. Cover cache miss/hit and slow-reader backpressure. This fault-injection reproduction was not performed; local tests are prohibited in this workspace and no remote test change was created for this diagnosis.
- Verify recovery with a deliberately damaged cached startup asset: startup failure should be visible, recovery must fetch valid assets, and native data clearing must renew the session rather than leaving 401. Verify this in real iOS Safari and the native WebView.
The user's reinstall removed the old native state. Without a new occurrence or reproducible fault injection, identical browser/native truncation cannot be proven retrospectively.
Suggested priority and effort
High: one user lost browser and native access until fresh asset retrieval or reinstall. Access is now recovered; the permanent prevention/recovery fix is still open. Breadth is unknown; no server data loss was reported.
AGENT GENERATED

Activity
[-]Mobile Connect stays blank or returns HTTP 401 despite re-pairing; Private-browser sign-in works[/-][+]Mobile Connect shows blank pages and HTTP 401/503; fresh Private-browser sign-in works[/+][-]Mobile Connect shows blank pages and HTTP 401/503; fresh Private-browser sign-in works[/-][+]iPhone Connect caches truncated startup JavaScript, causing persistent blank screen; native recovery hits 401[/+]bb-slop-cop commentedon Sep 22, 2026
🚨 SLOP COP 🚨 ·
new-issue-autopilotApplied Bug · High priority · Medium effort; preserved
bug,remote,connect, andmobile.Reproduction report: PARTIALLY REPRODUCED, medium root-cause confidence; label
partial-repro.A focused test failed identically in two clean main checkouts: after cookie removal, foreground renewal leaves a still-unexpired session authenticated with no cookies. Explicit session verification restores both stores. Existing scheduler tests (9) and encoding tests (6) pass. The original Safari truncation and native UI failure remain unverified by this investigation.
No PR: repairing the reproduced session-recovery gap changes authentication behavior, outside this rule’s simple-fix scope.