Skip to content

Blank session history after restart when summary diffs embed huge file contents #17622

Closed as not planned

Description

@wousp112

Summary

Large legacy message.summary.diffs[*].before/after payloads can make a non-empty session render as a blank history view after restart/reopen.

I hit this with a local session that still had:

  • 660 messages
  • 3344 parts
  • running tool parts = 0
  • latest completed message around 2026-03-15 15:40:58

but the desktop app reopened the session as an empty timeline.

Evidence

  • The affected session was not empty in SQLite.
  • 8 user messages embedded oversized summary.diffs[*].before/after payloads.
  • The largest single message.data row was about 79,009,021 bytes.
  • Total message.data for the session was about 345 MB.
  • The oversized summaries included .agent-history/EVENTS.jsonl / MANIFEST.json.

Root Cause

Snapshot.diffFull() currently returns full file contents in FileDiff.before/after, and those diffs are persisted into two places:

  1. session_diff storage via SessionSummary.summarizeSession()
  2. user.summary.diffs via SessionSummary.summarizeMessage()

That means a large text file diff can be written directly into message.data. When an old session is reopened, Session.messages() / MessageV2.page() hydrates those oversized rows and the renderer ends up trying to load a giant history payload just to render the timeline.

Expected

One oversized diff should not make a session unreadable. Session history should still open, and diff metadata should degrade safely.

Actual

The session title loads, but the timeline can come back blank after restart/reopen even though the session data is still present.

Proposed Fix

Two-layer fix:

  1. Write-side protection

    • bound inline FileDiff.before/after payloads
    • keep file, status, additions, deletions
    • record before_bytes, after_bytes, trimmed: true
    • clear inline contents when the payload is oversized
  2. Read-side protection

    • sanitize legacy oversized summary.diffs on read so old sessions become readable again without manual DB cleanup

I have a patch for this and can open a PR immediately.

Activity

  1. github-actions commented on Mar 15, 2026

    @github-actions
    Contributor

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

    • [FEATURE]: Store per-message diffs separately and lazy-load them #16741: Describes the same root cause — oversized summary.diffs[].before/after payloads embedded inline in MessageTable.data rows causing very large SQLite rows and degraded session loading performance. That issue proposes lazy-loading full diff contents and keeping only lightweight metadata inline on the message row, which aligns closely with the write-side protection described here.
  2. sjawhar commented on Apr 4, 2026

    @sjawhar

    Additional data from profiling a long-running opencode serve (100 sessions, 10 directories, 3+ hours):

    Heap snapshot analysis confirms FileDiff.before/after is the dominant JS heap consumer:

    • Snapshot at 2.5GB RSS: 355MB in a single diffs Array(22923) — 51% of JS heap
    • Snapshot at 11GB RSS: 7.64GB of strings (96% growth from diff content)
    • TUI snapshot: 22 copies of a 20MB JSON file retained by property:after

    On-disk session_diff sizes:

    593MB  ses_3217a01c8ffeGbwxVoc2sfyYvb.json
    593MB  ses_321604e22ffeISyOc0LrkFJPUr.json
    416MB  ses_70361c737dbd27DXqU8FuEWBoA.json
    44GB   total in ~/.local/share/opencode/storage/session_diff/
    

    Concrete example: A planning-only session (wrote 3 markdown files) had a 115MB session_diff containing 22 files — product catalogs, HTML fixtures, CSS — all from other agents' commits, not from the session itself (see also #11802).

    Heap snapshots and memleak traces available at: https://github.com/sjawhar/opencode/releases/tag/memory-leak-data

  3. removed
    webRelates to opencode on web / desktop
    on May 3, 2026
  4. github-actions commented on Jul 7, 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.

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