#8324·lens

Lens starts with a black window — renderer bundle aborts with net::ERR_INCOMPLETE_CHUNKED_ENCODING

Author: Elkhan246Created Aug 5, 2026Updated Aug 20, 2026
Labelsbug

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 both lens-main.log and lens-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 destroyed

Renderer state at that point, via CDP Runtime.evaluate:

json
{"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-gpu reproduces the black window identically (10152 ms, no renderer log).
  • Not window-state restore. Reproduces with window-state-for-first-application-window.json deleted, and with isFullScreen: 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, curl pulled 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: chunked with no Content-Length in 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.app absent from system DNS and from /etc/hosts (the bundled --host-resolver-rules=MAP lens.app 127.0.0.1 is 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=1 shifted 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:

  1. 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.
  2. Nothing is logged. lens-main.log contains 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.
  3. 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-Length for static assets instead of chunked encoding. With a known body length, a short read is detectable and recoverable; ERR_INCOMPLETE_CHUNKED_ENCODING as a failure class disappears.
  • Handle did-fail-load / webContents load 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 and errorCode/errorDescription. Today the absence of lens-renderer-root-frame.log is 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.log from paired good/bad sessions
  • the full CDP trace of a failing initial load
  • the scripts used (browser-level Target.setAutoAttach with waitForDebuggerOnStart, 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