Skip to content

OOM and ~30 GB database: huge workspace-file diffs embedded in message summaries are re-serialized in full on every message.updated event #43551

Closed as not planned

Description

@isHarryh

Description

When a text file in the OpenCode workspace keeps growing while a session is running (in my case an MCP server continuously appending its full API request/response log into the workspace — two log files reached 292 MB and 407 MB), OpenCode tracks the change and embeds the file's diff into message.summary.diffs on user messages.

This is compounded by the event store: every message.updated event re-serializes the entire message payload — including the huge embedded diff — as a new row in the event table. The same message is updated hundreds of times during a session, so the same multi-hundred-MB payload is written over and over.

Results:

  • opencode.db grew to 32.9 GB (event table alone: 29.4 GB)
  • OpenCode eventually crashed with OOM
  • Resuming the session crashes again with OOM, so the problematic session is permanently unopenable

Analysis

Measured on the 32.9 GB database:

table size
event 29,407 MB
message 1,121 MB
part 510 MB
WAL 771 MB
  • event holds 513k rows; 97.6% were written within ~8 hours.
  • Largest single event row: 362 MB (message.updated.1). Payload begins:
    {"sessionID":"ses_A","info":{...,"role":"user","summary":{"diffs":[{"file":"/logs/api_20260820.jsonl","patch":"Index: ...
    — the full unified diff of the 407 MB log file is embedded in the message.
  • 717 events exceed 1 MB (25.5 GB total); 135 events exceed 10 MB.
  • Session ses_A: 250 message.updated events for the same message, averaging ~33 MB each → 8.4 GB of byte-identical payloads. Top 3 sessions account for ~24 GB.

Root-cause chain

  1. A tool (here: an MCP server) continuously appends to a log file inside the workspace.
  2. OpenCode diffs the file against its snapshot and embeds the uncapped diff into message.summary.diffs.
  3. Every message.updated event stores a full copy of the message JSON in the event table (no truncation / dedup).
  4. The message is updated hundreds of times → hundreds of full-size copies → tens of GB.
  5. On session resume, giant messages are deserialized → OOM.

Steps to reproduce

  1. Start OpenCode TUI, assign a long task to OpenCode to let it keep running.
  2. Create a text file named test.txt in your OpenCode workspace.
  3. Start a program that appends 1 MB of text into that file every 1 or 2 seconds.
  4. Wait until OOM crash; restarting and resuming the session crashes again.

Diagnostics SQL:

SQL queries used

SELECT name, sum(pgsize)/1048576.0 AS mb FROM dbstat GROUP BY name ORDER BY mb DESC;
SELECT length(data)/1048576 AS mb, type, aggregate_id FROM event ORDER BY length(data) DESC LIMIT 10;
SELECT aggregate_id, count(*), sum(length(data))/1048576 AS mb FROM event GROUP BY aggregate_id ORDER BY mb DESC LIMIT 10;

Plugins

None

OpenCode version

1.18.18

Screenshot and/or share link

The problematic session cannot be opened anymore.

Operating System

Windows 11 (24 GB RAM)

Terminal

Powershell 7.8

Activity

  1. github-actions commented on Aug 20, 2026

    @github-actions
    Contributor

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

    The root cause appears to be the same: the event table accumulates full message snapshots without any retention or compaction, which your large file being tracked would rapidly accelerate.

  2. changed the title [-]OOM happened when a OpenCode tracked file's size grew to very large[/-] [+]OOM and ~30 GB database: huge workspace-file diffs embedded in message summaries are re-serialized in full on every `message.updated` event[/+] on Aug 20, 2026
  3. DScoNOIZ commented on Sep 20, 2026

    @DScoNOIZ

    Confirming this exact failure mode on opencode-desktop 1.18.31 (Linux, Manjaro), engine at dev ebb7b76ec.

    Measurements on my opencode.db (1.1 GB): event table 797 MB, of which 100 rows >1 MB = 555 MB. Largest single rows ~77 MB (message.updated.1). All from one session whose message.summary.diffs embedded full unified diffs of solver output files (foam_barrel_2d/<time>/U field files, project without git history so git-ignore filtering didn't apply).

    Code path confirmed in source: packages/opencode/src/session/summary.ts:98 (computeDiff → snapshot.diffFull) → packages/opencode/src/snapshot/index.ts:736-737 (structuredPatch(..., { context: Number.MAX_SAFE_INTEGER }), no per-file or total byte limit) → packages/opencode/src/session/session.ts:629 (updateMessage publishes full info incl. the giant summary.diffs on every message.updated, each persisted as a new event row). Related: #33356 (no retention), #46138 (diffFull full patch text), #50089 (heap on resume).

    Workaround that recovered my instance: DELETE FROM event WHERE LENGTH(data) > 1000000 (100 rows) + PRAGMA wal_checkpoint(TRUNCATE) + VACUUM → 1146 MB → 586 MB, integrity_check: ok, all sessions intact. Note for #43456: plain VACUUM in WAL mode spiked the WAL to ~590 MB mid-operation before the checkpoint reclaimed it — supporting the VACUUM INTO + swap approach.

    Suggested fix direction: cap diff output (per-file + total bytes, keep numstat counts truthful, append [truncated] marker) at the diffFull emit loop; all patch consumers I could find are display-only, and patch is already optional in the schema, so truncation should be safe.

  4. craigvandotcom commented on Sep 22, 2026

    @craigvandotcom

    Another data point on 1.18.31 (unchanged in 1.18.32): opencode.db hit 82 GB, up from 6.9 GB about ten days earlier.

    • event is 76 GB of it. message.updated.1 rows account for 75.7 GB across 65,688 rows (mean 1.15 MB, max 31 MB). All other event types together come to about 330 MB.
    • Nearly all of that is info.summary.diffs[].patch for one file: a 31 MB, git-tracked .beads/issues.jsonl. Because diffFull() uses context: Number.MAX_SAFE_INTEGER, a +22/−21 line change produces a ~30 MB patch. summarize() then writes that patch into a new event row on every message update. One parent session and its subagents wrote 56 GB in a single day.
    • The 2 MB guard in snapshot/index.ts applies only to untracked files, so a large tracked file is never capped.
    • Aggregate queries over event (for example sum(length(data)) grouped by type) get OOM-killed on a 27 GB machine.

    Workaround that keeps undo/revert: add the file to the repo's .git/info/exclude. snapshot.ignore() runs git check-ignore --no-index, which matches tracked files too, so they drop out of diffFull(). Combined with stripping the old payloads (UPDATE event SET data = json_remove(data, '$.info.summary.diffs') WHERE type = 'message.updated.1', then VACUUM, with opencode stopped), this reclaims the space.

    What would fix it for everyone: bounded context in diffFull, a size cap that also covers tracked files, and not re-serializing unchanged diffs into each durable event (#42748, #50106).

  5. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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