Lens starts with a black window — renderer bundle aborts with net::ERR_INCOMPLETE_CHUNKED_ENCODING
Bug report: Lens starts with a black window — renderer bundle aborts with net::ERR_INCOMPLETE_CHUNKED_ENCODING
To: [email protected] / https://github.com/lensapp/lens/issues Severity: High — Lens is completely unusable when it happens; the only user-visible signal is a black window with no error message.
Summary
Intermittently (for me: for hours at a time, across every relaunch) Lens opens with a
fully black content area. The native menu bar and window chrome work; the UI never
renders. There is no error message, no crash report, and nothing in lens-main.log
that identifies a failure.
I traced it with the Chrome DevTools Protocol. The cause is that the renderer's main bundle request fails partway through:
Network.loadingFailed https://lens.app:<port>/build/lens.js
errorText = net::ERR_INCOMPLETE_CHUNKED_ENCODING
canceled = false
received = 10,419,815 of 29,587,435 bytes (35.2%)lens.js never executes, so nothing mounts into #app, the renderer never signals
readiness, and lens-core-main:show-initial-window gives up on a fixed 10-second
timeout and shows an empty window.
Because the script aborts rather than throws, no exception reaches
Runtime.exceptionThrown and no renderer-side logging ever initializes — which is why
the failure is completely silent in the logs.
Environment
| Lens | 2026.6.260931-latest (com.electron.kontena-lens) |
| macOS | Darwin 25.6.0, Apple Silicon, built-in display only |
| Profile | ~/Library/Application Support/Lens |
| Network | no system proxy, no VPN client, no system extensions, no security agents |
| Disk | 224 GB free |
A reliable way to tell a good launch from a bad one
This is the cleanest diagnostic I found, and it may help triage other reports:
- Good launch → the session directory under
~/Library/Logs/Lens/<ts>/contains bothlens-main.logandlens-renderer-root-frame.log. - Bad launch → it contains only
lens-main.log. The renderer logger is itself part of the bundle that never ran.
Two derived metrics separate the two modes with zero overlap across 44 recorded sessions on my machine:
| Metric | Good launch | Black window |
|---|---|---|
lens-core-main:show-initial-window |
1591–1859 ms | 10043–10169 ms (fixed timeout) |
Loading content for window "first-application-window" → Window … loaded |
1439–1606 ms | 183–296 ms |
lens-renderer-root-frame.log |
present | absent |
The bad launches are faster, because the 29.5 MB bundle is abandoned at ~35% instead of being fetched, parsed and executed.
Timeline of a failing launch (from lens-main.log):
20:45:20.021 Starting v2026.6.260931-latest of Lens...
20:45:20.076 [INTERNAL-PROXY-MAIN]: Proxy server has started at 127.0.0.1:56915
20:45:20.160 ⚡ LensProxy connection OK
20:45:20.369 [ELECTRON-WINDOW]: Loading content for window "first-application-window"
from url: https://lens.app:56915...
20:45:20.604 [ELECTRON-WINDOW]: Window "first-application-window" loaded ← 235 ms
20:45:21.880 [TOKEN-REFRESHER]: New tokens saved to store...
────────── 8.6 seconds of complete silence ──────────
20:45:30.485 runnables "after-application-is-loaded" took 10169.12 ms
- lens-core-main:show-initial-window 10152.43 ms ← timeout
20:45:30.492 [ELECTRON-WINDOW]: webContents for "splash" has been destroyedRenderer state at that point, via CDP Runtime.evaluate:
{"readyState":"complete","url":"https://lens.app:57775/",
"appChildren":0,"bodyChildren":3,"globals":249,
"resources":[{"name":"lens.css","status":200},{"name":"lens.js","status":200}]}globals: 249 — the bundle contributed nothing. On a launch where the same page is
reloaded successfully, that number is 12917 and appChildren is 1.
What I ruled out
Each of these was tested directly, not assumed:
- Not the GPU / compositor.
--disable-gpureproduces the black window identically (10152 ms, no renderer log). - Not window-state restore. Reproduces with
window-state-for-first-application-window.jsondeleted, and withisFullScreen: false. - Not the on-disk caches. Reproduces immediately after deleting
Cache,Code Cache,GPUCache,DawnGraphiteCache,DawnWebGPUCache. - Not LensProxy, and not the file. While the renderer was failing,
curlpulled all 29,587,435 bytes from the same proxy, same port, repeatedly — including concurrently with app startup, and with browser-shaped headers (Accept-Encoding: gzip, deflate, br, zstd, Chromium UA,Sec-Fetch-Dest: script). - Not server-side backpressure. A raw TLS client that deliberately reads slowly
(16 KB chunks with 10 ms pauses, 22.5 s total) still receives the complete body.
The response is
Transfer-Encoding: chunkedwith noContent-Lengthin all cases. - Not resource exhaustion. 75% memory free, 224 GB disk free.
- Not the environment. No proxy (
scutil --proxy), no system extensions, no content filters,lens.appabsent from system DNS and from/etc/hosts(the bundled--host-resolver-rules=MAP lens.app 127.0.0.1is doing its job — the renderer is on the correct URL). - Not truncation of the asset itself. On a successful load,
encodedBodySize == decodedBodySize == 29587435, matching the on-disk size exactly.
So: the server sends the whole body, and Chromium's network stack inside Lens reports the chunked stream as ending early. I could not narrow it further from outside the app.
Two data points that may help you localize it:
--disk-cache-size=1shifted the odds noticeably (2 of 3 launches succeeded while plain launches were failing 100% of the time), but it is not a reliable fix — the third launch with the flag still went black. That it moves the needle at all suggests the HTTP cache layer is involved.- The state is sticky. It stays broken across many consecutive relaunches for hours, then clears — sometimes on reboot, sometimes on its own (my logs show recovery without a reboot on 15 Jul and 26 Jul).
Why this is worse than it needs to be
Independently of the root cause, the failure mode itself is the real problem:
- A subresource load failure silently degrades into a blank window. The main process knows the renderer never signalled readiness — it waits exactly 10 s for it — and then shows the window anyway, with no message.
- Nothing is logged.
lens-main.logcontains no hint. The renderer cannot log, because its logger lives inside the bundle that failed to load. From a user's point of view Lens is simply broken with zero diagnostics. - A single 29.5 MB uncompressed chunked response is a large, fragile thing to depend on for the app to exist at all, with no retry.
Suggested fixes
- Send
Content-Lengthfor static assets instead of chunked encoding. With a known body length, a short read is detectable and recoverable;ERR_INCOMPLETE_CHUNKED_ENCODINGas a failure class disappears. - Handle
did-fail-load/webContentsload errors on the app window — retry the navigation at least once before giving up. - Replace the silent 10 s timeout with a visible error state ("Failed to load the Lens UI — Retry / Open logs") instead of an empty window.
- Log renderer load failures in
lens-main.log, including the failed URL anderrorCode/errorDescription. Today the absence oflens-renderer-root-frame.logis the only signal, which is not discoverable. - Consider compressing and/or splitting the renderer bundle. 29.5 MB served uncompressed over the local proxy on every cold start is a lot of exposure.
Attachments I can provide on request
lens-main.logfrom paired good/bad sessions- the full CDP trace of a failing initial load
- the scripts used (browser-level
Target.setAutoAttachwithwaitForDebuggerOnStart, so the renderer is frozen before it executes anything and the first navigation is captured in full)
Here's md file lens-black-window-bug-report.md
Source: lensapp/lens