Skip to content

TUI hangs indefinitely when resuming sessions with large file diffs (formatPatch/structuredPatch blocks event loop) #23362

Closed as not planned

Description

@sim590

Description

When resuming certain sessions that contain many file modifications and resending a message, the TUI freezes completely (no response to ESC or any input). The hang is deterministic and reproducible.

Root Cause

The hang is caused by formatPatch(structuredPatch(..., { context: Number.MAX_SAFE_INTEGER })) from the diff npm package, called synchronously inside Snapshot.diffFull().

Call chain

  1. prompt.ts — SessionSummary.summarize() is called fire-and-forget at step 1 of the processor
  2. summarize → computeDiff → snapshot.diffFull(from, to)
  3. diffFull calls formatPatch(structuredPatch(file, file, before, after, "", "", { context: Number.MAX_SAFE_INTEGER })) synchronously for each changed file
  4. structuredPatch with Number.MAX_SAFE_INTEGER context lines blocks the main thread indefinitely on sessions with many file modifications
  5. The TUI freezes — the event loop is blocked, all threads end up in FUTEX_WAIT

Evidence

  • strace confirms async deadlock: all threads idle in FUTEX_WAIT, 0% CPU
  • Commenting out SessionSummary.summarize() in prompt.ts → fixes the hang
  • Replacing formatPatch(structuredPatch(...)) with git diff subprocess → fixes the hang
  • Replacing with an inline string template (no diff package) → fixes the hang

Regression Commit

Identified via git bisect (9 steps between v1.3.3 and HEAD):

b7fab49b6 — refactor(snapshot): store unified patches in file diffs (#21244)

Parent commit 463318486 is the last good commit.

Proposed Fix

Replace the synchronous formatPatch(structuredPatch(...)) call with a git diff subprocess:

const diff = yield* git(
  [...quote, ...args(["diff", "--no-ext-diff", "--no-renames", from, to, "--", ...run.map((r) => r.file)])],
  { cwd: state.directory },
)
const patches = new Map<string, string>()
if (diff.code === 0 && diff.text.trim()) {
  const parts = diff.text.split(/^(?=diff --git )/m)
  for (const part of parts) {
    if (!part.trim()) continue
    const match = part.match(/^diff --git a\/(.+?) b\//)
    if (match) patches.set(match[1], part.trim())
  }
}

This runs in a subprocess (non-blocking), is faster for large diffs, and eliminates the problematic diff package dependency for this code path.

Reproduction

  1. Have a session with many file modifications (e.g. an agent session that edited 10+ files)
  2. Fork that session
  3. Resend the last message
  4. The TUI freezes immediately and never recovers

Environment

  • Linux x86_64, Bun
  • OpenCode versions after commit b7fab49b6 (post v1.3.3)

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    perfIndicates a performance issue or need for optimization
    on Apr 19, 2026
  2. github-actions commented on Apr 19, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of an existing issue. Please check:

  3. sim590 commented on Apr 19, 2026

    @sim590
    Author

    Closing as duplicate of #22650 — same root cause (formatPatch(structuredPatch(..., { context: Number.MAX_SAFE_INTEGER })) in snapshot/index.ts). Adding our findings as a comment on #22650.

  4. sim590 commented on Apr 19, 2026

    @sim590
    Author

    Reopening: although this is likely a duplicate of #22650 (same root cause in snapshot/index.ts), we cannot fully confirm equivalence since #22650 covers the web/desktop path while this issue was identified and verified on the TUI path only. Keeping this open as the target for #23366.

  5. reopened this on Apr 19, 2026
  6. assigned and unassigned on Apr 26, 2026
  7. removed
    perfIndicates a performance issue or need for optimization
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  8. github-actions commented on Jul 4, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

  9. sim590 commented on Aug 22, 2026

    @sim590
    Author

    @rekram1-node: this issue still occurs. It has not been addressed.

    It is impossible to interrupt the LLM. It is stuck and pressing ESC only toggles the bottom message and the process never gets interrupted:

    Image

    #23366 fixes this. Please consider looking at the PR.

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