Skip to content

chat: recover from V8 max-string-length when persisting session state#319183

Merged
roblourens merged 2 commits into
mainfrom
roblou/fix-308843-chat-rangeerror
Jun 1, 2026
Merged

chat: recover from V8 max-string-length when persisting session state#319183
roblourens merged 2 commits into
mainfrom
roblou/fix-308843-chat-rangeerror

Conversation

@roblourens
Copy link
Copy Markdown
Member

Fixes #308843.

Problem

JSON.stringify of the full chat session state could throw RangeError: Invalid string length during compaction, losing the entire chat session. The session-store mutation log compacts every 1024 entries by writing a single Initial entry containing the full serialized state; with multiple large tool result values stored under IChatAgentResult.metadata.toolCallResults (notably Copilot's read_page tool, whose results can be ~60 MiB each), the combined JSON exceeded V8's ~512 MiB max string length.

Field forensics in the issue showed one tool result alone at ~61 MiB and a JSONL log file at ~640 MiB with one line at ~503 MiB before serialization eventually failed.

Fix

Wrap the three JSON.stringify(entry) call sites in ObjectMutationLog with stringifyEntryWithFallback, which:

  • Common path: a single JSON.stringify — zero overhead.
  • Failure path: on RangeError, retry with a truncating replacer that caps individual strings at 1 MiB and the total tracked size at 100 MiB. Oversized values are replaced with a clear marker (e.g. [VS Code: value truncated for persistence; original 314572800 chars]).
  • Non-RangeError exceptions (circular refs, etc.) propagate unchanged.

The fix lives at the engine level rather than in the chat schema, so:

  • The common path doesn't pay any pre-walk cost.
  • It's generic — defends against any future schema field that could grow unbounded, not just result.
  • The schema and live ChatModel are unchanged.

Copilot's prompt path already replaces tool results > 8 KiB with on-disk file references when building prompts, so a truncated persisted copy has no functional impact on conversation resume — only the unbounded "for the record" copy is affected.

Notes for reviewers

  • Cap sizing rationale: 1 MiB per string is dramatically larger than any legitimate single string in chat state; 100 MiB total leaves ample headroom under V8's ~512 MiB limit even on extreme sessions.
  • Tests use a toJSON() hook to trigger a real RangeError mid-stringify without requiring 300+ MiB allocations — fast (<10 ms) and exercises the actual catch+retry path. I also verified end-to-end against an actual V8 RangeError locally (allocating a 300 MiB string referenced twice in an object) and confirmed full recovery through createInitial + read round-trip.
  • Truncation only takes effect on actual failure; sessions in normal use are byte-for-byte identical to before.

(Written by Copilot)

JSON.stringify on the full session state (every 1024 mutations during
compaction) could exceed V8's ~512 MiB max string length when extensions
stored very large content in IChatAgentResult.metadata.toolCallResults
(notably Copilot's read_page tool can produce ~60 MiB browser dumps).
The thrown RangeError propagated up and lost the entire chat session.

Wrap the JSON.stringify(entry) calls in ObjectMutationLog with a catch
for RangeError that retries with a replacer truncating strings over
1 MiB and capping total at 100 MiB. The common path is a single
JSON.stringify with zero overhead; only failures pay the recovery cost.
Generic across the whole schema, so any future field that grows is
also protected.

Fixes #308843.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

(Written by Copilot)
Copilot AI review requested due to automatic review settings May 31, 2026 01:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens chat session persistence against V8’s max string length limit by adding a fallback serialization path in the chat session mutation log, preventing entire sessions from being lost when a compaction write would otherwise throw RangeError: Invalid string length.

Changes:

  • Added stringifyEntryWithFallback to retry JSON.stringify with a truncating replacer after RangeError.
  • Introduced a stateful truncating replacer that caps individual strings and enforces an overall serialization budget on retry.
  • Added unit tests covering truncation behavior and the RangeError retry path.
Show a summary per file
File Description
src/vs/workbench/contrib/chat/common/model/objectMutationLog.ts Wraps log entry serialization with a RangeError recovery path and adds truncation helpers/constants.
src/vs/workbench/contrib/chat/test/common/model/chatSessionOperationLog.test.ts Adds tests validating truncation and fallback stringify behavior.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 2

Comment thread src/vs/workbench/contrib/chat/common/model/objectMutationLog.ts Outdated
Comment thread src/vs/workbench/contrib/chat/common/model/objectMutationLog.ts Outdated
Copilot reviewer noted:
- Constants were named _BYTES but track string.length (UTF-16 code units),
  and the 'guaranteed to succeed' claim ignored JSON escaping and keys.
  Renamed to _CHARS and clarified that the budget is approximate.
- makeTruncatingReplacer checked total >= maxTotalChars *before* counting
  the current string, so one extra under-cap string could overshoot the
  cap. Now projects (total + val.length + 2) and emits the truncation
  marker if it would exceed the budget.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

(Written by Copilot)
@roblourens roblourens marked this pull request as ready for review May 31, 2026 21:26
@roblourens roblourens enabled auto-merge (squash) May 31, 2026 21:26
@roblourens roblourens merged commit eb308be into main Jun 1, 2026
25 checks passed
@roblourens roblourens deleted the roblou/fix-308843-chat-rangeerror branch June 1, 2026 00:03
@vs-code-engineering vs-code-engineering Bot added this to the 1.123.0 milestone Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error serializing chat session for storage.

3 participants