Skip to content

App frequently becomes unresponsive when opening a session in Desktop V2 #51423

Closed

Description

@HexStan

Description

As stated in the title.

From my observation, the trigger seems completely random: the same session can sometimes open normally, but other times it immediately freezes upon opening; sometimes the issue doesn't occur even after prolonged use, while other times it freezes right when opening the very first session.

When it becomes unresponsive, nothing is clickable except for the buttons in the title bar. After a while, a "Not Responding" dialog pops up.

Plugins

None

OpenCode version

All versions since I upgraded to V2, including the latest 2.0.18

Steps to reproduce

  1. Upgrade from Desktop V1 to V2
  2. Open OpenCode and wait for the data migration to complete
  3. Open any session

Screenshot and/or share link

opencode-debug-20260926T001640.zip

Image

Operating System

Windows 11

Terminal

No response

Activity

  1. github-actions commented on Sep 26, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:\n- #51028: Windows Desktop V2 renderer becomes unresponsive around startup, with V1-to-V2 store migration also noted.\n- #36379: Desktop renderer hangs when opening sessions with very large message histories.

  2. HexStan commented on Sep 26, 2026

    @HexStan
    Author

    Additional Note: This issue also occurs even with sessions created after upgrading to V2.

  3. HexStan commented on Sep 26, 2026

    @HexStan
    Author

    Analysis of the attached debug bundle (opencode-debug-20260926T001640.zip)

    I went through the logs from the debug export and sharing the findings in case they help triage.

    The freeze is renderer-side, not backend/service-side

    • main.log is clean in every session: startup, v2 CLI/service startup, and the V1→V2 data migration all complete normally.
    • server-1/opencode.log (~62k lines) shows nothing at the freeze timestamps; its only ERROR entries are from June and unrelated (aborted runs).
    • Every freeze is recorded in window.log as renderer unresponsive for the main window.

    The unresponsive events fire exactly when a session is opened

    In 5 of the 14 captured sessions, window.log logged renderer unresponsive — each one ~20 s after app start, i.e. right when the first session was opened (times below are local):

    Session dir app starting (main.log) first renderer unresponsive (window.log)
    20260925T235418 07:54:18 07:54:39
    20260926T001134 08:11:34 08:11:54
    20260926T001612 08:16:13 08:16:40

    Sampled stacks all land in the message list's stick-to-bottom virtualizer path

    The renderer unresponsive samples captured by the main process always point at the same code path — a virtualized list (looks like TanStack Virtual) performing scrollToEnd on mount/measurement:

    at Array.Re (oc://renderer/assets/main-C8RBRwI4.js:2:12238)
    at Object.active (oc://renderer/assets/route-CHhjG5_X.js:89:64925)
    at n (oc://renderer/assets/route-CHhjG5_X.js:89:51650)
    at Object.scrollToFn (oc://renderer/assets/route-CHhjG5_X.js:89:53808)
    at Ba._scrollToOffset (oc://renderer/assets/route-CHhjG5_X.js:2:44160)
    at Ba.scrollToIndex (oc://renderer/assets/route-CHhjG5_X.js:2:42710)
    at Ba.scrollToEnd (oc://renderer/assets/route-CHhjG5_X.js:2:43143)
    

    Other samples enter the same class from different entry points: Ba.scheduleScrollReconcile, Ba.getOffsetForIndex, P.resizeItem. Bundle hashes differ between builds (route-CDROkuzn.js, route-D7t6Qi_B.js, route-CHhjG5_X.js) but the offsets are identical, so it is the same code across 2.0.x.

    renderer.log shows a ResizeObserver storm

    Sessions that froze show bursts of ResizeObserver loop completed with undelivered notifications, up to 248 lines in a single session:

    • 20260925T235000: 248
    • 20260925T235534: 205
    • 20260925T152241: 74

    One possibly relevant detail: renderer.log starts with Slow network is detected. … Fallback font will be used while loading: oc://renderer/assets/Inter.ttf. If the webfont swaps in after the list has already measured and scrolled, item heights change post-measurement — exactly the kind of event that would kick off a measure → scroll → measure loop.

    How this explains the reported symptoms

    • Freeze on session open: the list mounts and sticks to the bottom; item heights change (late font swap, code blocks/diffs/images) → ResizeObserver re-measures → scrolls again → the loop pegs the renderer main thread at 100%.
    • Randomness: whether the loop converges depends on font-load timing, item height variance, and window size — so the same session sometimes opens fine.
    • Title bar stays clickable: the native caption buttons are handled by the OS, not by the frozen renderer.

    Relation to existing issues

    This looks like the same family as #33712, #34289, #34038, #37997, #38296, #43355, #48633. One difference that may be useful for triage: in my captures the sampled stacks sit in the session message list virtualizer (scrollToEnd stick-to-bottom), not in the composer-region observers analyzed in #33712. Also note PR #44883 only suppresses the ResizeObserver log noise — the freeze itself still reproduces on 2.0.18.

    Happy to provide additional logs if needed.

  4. natsforai-lab commented on Oct 19, 2026

    @natsforai-lab

    Additional reproduction on Windows 11 with desktop 2.0.32 (latest per the updater; fresh NSIS install).

    Environment

    • opencode desktop 2.0.32, Windows 11 Home (build 26200), x64, Intel i5-1335U, 15.7 GB RAM
    • No third-party plugins that affect rendering
    • Local DB integrity checked (PRAGMA quick_check = ok) — this is not a corrupt-store problem

    Symptom

    The renderer becomes unresponsive 17–18 seconds after launch, while the first session's message list is rendering. The main-process watchdog logs renderer unresponsive and then collects stack samples; the UI stays wedged and has to be force-killed.

    Occurrences on 2026-10-19 (local time, UTC+5:30), each on a fresh launch:

    • 08:10:09 (launched 08:09:51)
    • 08:12:02 (launched 08:11:44)
    • 21:54:29 (launched 21:54:12)
    • 21:56:57 (launched 21:56:39)

    Two consecutive launches froze exactly 17 s and 18 s after process start. A later launch restored the same session without freezing, so this is timing-dependent, not purely data-dependent. The session opened was moderate in size (~550 messages, ~1,600 parts).

    Evidence

    window.log — renderer unresponsive samples (repeating):

    at Ag.M.resizeItem (oc://renderer/assets/route-BYzALZ62.js:9:54530)
    at Ag.M.resizeItem (oc://renderer/assets/route-BYzALZ62.js:9:57988)
    at Map.forEach (<anonymous>)
    at Ag.M.resizeItem (oc://renderer/assets/route-BYzALZ62.js:9:57959)
    at Object.me (oc://renderer/assets/main-CZyBNj5O.js:2:5071)
    at Map.delete (<anonymous>)
    at Ag.M.resizeItem (oc://renderer/assets/route-BYzALZ62.js:9:54640)
    

    Same measure/resize ↔ scroll-to-end loop in the message-list virtualizer described above (resizeItem, _scrollToOffset, scrollToIndex).

    renderer.log also contains repeated:

    ResizeObserver loop completed with undelivered notifications
    

    and at startup (before the first session renders):

    Slow network is detected. ... Fallback font will be used while loading: oc://renderer/assets/Inter.ttf
    

    which is consistent with the late-webfont-swap theory (items re-measured after the first layout pass).

    Notes

    • Force-kill + relaunch reproduces it reliably; the freeze always lands ~20 s after start, never later in the session.
    • Happy to attach the full debug bundle (opencode-debug-20261019T162611.zip, ~500 KB) if useful.
  5. natsforai-lab commented on Oct 19, 2026

    @natsforai-lab

    Root cause found + a working local fix (2.0.32, Windows)

    Following up on the earlier evidence dump: the hang is not GPU, not the session data, and not the DB. It is a chat virtualizer microtask busy-loop in the renderer.

    What the watchdog samples show

    The Electron "renderer unresponsive" stacks always land in the same two places (bundled renderer asset route-BYzALZ62.js):

    at Array.eee (main-CZyBNj5O.js:2:12239)
    at Object.active (route-BYzALZ62.js:10:9061)
    at n (route-BYzALZ62.js:9:51932)
    at Ag.M.resizeItem (route-BYzALZ62.js:9:54542)          <- overridden resizeItem
    at route-BYzALZ62.js:9:57988
    at Map.forEach (<anonymous>)
    at route-BYzALZ62.js:9:57959                            <- measure-all loop (je)
    at ke (route-BYzALZ62.js:9:57631)                       <- tail auto-scroll
    at route-BYzALZ62.js:9:58058
    at le (route-BYzALZ62.js:9:53365)                       <- observeElementOffset callback
    at ke (route-BYzALZ62.js:9:57663)
    at route-BYzALZ62.js:9:58058
    

    The loop

    je() (the tail/measure pass) queues a queueMicrotask that measures every mounted chat row through the overridden M.resizeItem, and the resize-apply microtask ends by calling ke() (tail auto-scroll) and then je() again. Each iteration mounts/measures/scrolled content that queues another microtask. Because the chain never yields to the event loop, timers never run — including whatever marks markdown blocks data-markdown-ready. The tail mode only exits when everything is measured and no markdown block is pending (ce.querySelector('[data-component="markdown"]:not([data-markdown-ready])')), so the pane stays visibility: hidden (the blank window) while memory climbs to 1–3 GB.

    Throttling MutationObserver/ResizeObserver from the outside does not help — the loop is driven by microtasks, not observer delivery.

    Local fix (one line in the renderer bundle)

    Debounce the measure microtask so the cycle can never run tighter than 150 ms and always yields to the event loop:

    // out/renderer/assets/route-BYzALZ62.js, inside je():
    // before
    queueMicrotask(()=>{Ee=!1;let t=d();
    // after
    queueMicrotask(()=>{Ee=!1;if(globalThis.__ocJT&&performance.now()-globalThis.__ocJT<150)return;globalThis.__ocJT=performance.now();let t=d();

    Result on the same machine and app build: an 800k-token session (529 messages, the same class of session that froze before) renders, scrolls and stays responsive; renderer idles around 70 MB heap / ~0% CPU, and the chat pane becomes visible in about a second. Cold starts no longer hang.

    Happily re-testing any official fix — but the underlying issue looks like the tail-mode completion condition (markdown-ready + measurement settling) can be starved by the measurement microtask chain itself, so a yield/debounce in that path (or dropping visibility:hidden while waiting) would be the place to patch upstream.

  6. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed report and the log analysis, and thanks to @natsforai-lab for the extra reproduction on 2.0.32.

    I couldn't try to reproduce this here: it needs the desktop app on Windows, and the sandbox I run in is headless Linux, so a maintainer with that setup will need to confirm it.

    The code path in your stack samples is still on the current dev branch, in the session timeline's 'scroll to the bottom on open' handling. That fits the measure → scroll → measure loop you and @natsforai-lab described. Your timings, stack samples and the note that the debounce workaround stops the hang should help whoever looks at it.

    Related issues (none of them looks like the same cause):

  7. Hona commented on Oct 30, 2026

    @Hona
    Member

    Fixed in v2.2.1+ (#60034). Under fractional OS display scaling (125%/150%/175%) or desktop zoom, Chromium stops scrolling ~1-2px short of scrollHeight - clientHeight, which wedged the timeline virtualizer cold-mount settle microtask loop (scrollToEnd <-> resizeItem) when opening a session. Thank you all for the detailed stack samples and root-cause analysis - please update to v2.2.1 or newer (v2.2.2 is current) and let us know if you still see any hangs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions