From 65ef17b2f71cb7ab2a7f798e1bfd781c8f56a353 Mon Sep 17 00:00:00 2001 From: Zexi Date: Fri, 15 May 2026 05:09:45 +0200 Subject: [PATCH] fix: prevent sidecar crash when apply_patch deletes a large/binary file When deleting a file via apply_patch, the entire file content was passed to createTwoFilesPatch and the resulting diff stored verbatim in SQLite. For a 142 MB binary file this produces a ~380 MB string; Node's sqlite module then passes it to v8::String::NewFromUtf8 which hits V8's internal string-length assertion and SIGTRAPs the sidecar process. Guard both the delete path in apply_patch.ts (skip diff generation when content > 512 KB) and trimDiff in edit.ts (early-return empty string when the diff itself already exceeds 512 KB). Closes #27657 --- packages/opencode/src/tool/apply_patch.ts | 8 +++++++- packages/opencode/src/tool/edit.ts | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index 84e84cc3962e..f57b9328ab8f 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -169,7 +169,13 @@ export const ApplyPatchTool = Tool.define( ), ) const contentToDelete = source.text - const deleteDiff = trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, "")) + // Skip diff for large/binary files to prevent storing hundreds of MB in SQLite. + // V8 string limit is ~512MB; a 142MB binary file produces a 380MB+ diff. + const DIFF_SIZE_LIMIT = 512 * 1024 // 512 KB + const deleteDiff = + contentToDelete.length > DIFF_SIZE_LIMIT + ? "" + : trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, "")) const deletions = contentToDelete.split("\n").length diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index ea3aac34807d..7d676f65b15c 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -635,7 +635,10 @@ export const ContextAwareReplacer: Replacer = function* (content, find) { } } +const DIFF_MAX_BYTES = 512 * 1024 // 512 KB — keeps SQLite rows manageable and well under V8's string limit + export function trimDiff(diff: string): string { + if (diff.length > DIFF_MAX_BYTES) return "" const lines = diff.split("\n") const contentLines = lines.filter( (line) =>