You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
apply_patch forces a trailing newline onto files that lacked one #45912
packages/core/src/patch.tsderive() unconditionally appends a trailing newline to the result: if (updated.at(-1) !== "") updated.push("").
So apply_patch on a file that lacks a trailing newline adds one even when the patch doesn't touch the last line. patchFile then diffs before (no trailing newline) against after (with one), reporting a change the model never requested.
This issue might be a duplicate of (or closely related to) an existing issue. Please check:
apply_patch deletes the final blank line of files that end with one #42081: Reports the inverse behavior in the same function — derive() in packages/core/src/patch.ts drops a trailing blank line from files that end with \n\n. Both issues trace back to the same EOF-sentinel logic in derive() and likely need to be fixed together.
I work in a large repo where we have a .editorconfig setting which prohibits trailing newlines at the end of the file. When we use our formatter, it then triggers on every file apply_patch is applied to, which adds significant churn. Is there a way to ignore changes to the end of the file if none were made, or to otherwise follow repository conventions?
Thanks for the clear report. I could reproduce this.
Steps: a project with f.txt containing line1\nline2\nline3 and no final newline, and a simulated GPT model that calls the patch tool to change only line1 to LINE1. After the patch:
the tool's own "Patched f.txt" diff shows line3 removed and added again;
git diff shows \ No newline at end of file only on the old side;
od -c shows the file now ends with 3 \n.
The recording and screenshots below show this, and the script below reproduces it. It happens on 2.2.0 and still happens on the latest dev (506ac20). The cause is the line in derive() (now in packages/util/src/patch.ts) that always adds a final newline, whatever the original file ended with.
// Repro for anomalyco/opencode#45912: the patch (apply_patch) tool adds a trailing// newline to a file that had none, even though the patch only edits line 1.// Run: OPENCODE_DRIVE_MEDIA_DIR=/workspace/media opencode-drive run drive.ts// (set OC_DEV=/path/to/opencode/checkout to run from source)import{Effect,Stream}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"constpatchText="*** Begin Patch\n*** Update File: f.txt\n@@\n-line1\n+LINE1\n*** End Patch"constcheck="git diff f.txt; od -c f.txt"exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true},// f.txt has NO trailing newlineproject: {git: true,files: {"f.txt": "line1\nline2\nline3"}},},({ ui, llm })=>Effect.gen(function*(){letstep=0yield*llm.serve((request: any)=>{if(!request.body?.tools?.length||JSON.stringify(request.body?.messages??"").includes("You name conversations"))returnStream.make(Llm.text("Patch EOF newline"))// title requeststep++if(step===1)returnStream.make(Llm.toolCall({index: 0,id: "call_patch",name: "patch",input: { patchText }}),Llm.finish("tool-calls"))if(step===2)returnStream.make(Llm.toolCall({index: 0,id: "call_check",name: "shell",input: {command: check,description: "Show diff and bytes"}}),Llm.finish("tool-calls"),)returnStream.make(Llm.text("Done checking."))})yield*ui.submit("Uppercase line1 in f.txt")yield*ui.waitFor("Done checking.")yield*Effect.sleep("2 seconds")yield*ui.screenshot("after-patch")}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Activity
github-actions commentedon Aug 28, 2026
This issue might be a duplicate of (or closely related to) an existing issue. Please check:
derive()inpackages/core/src/patch.tsdrops a trailing blank line from files that end with\n\n. Both issues trace back to the same EOF-sentinel logic inderive()and likely need to be fixed together.maplemuse commentedon Sep 1, 2026
I work in a large repo where we have a .editorconfig setting which prohibits trailing newlines at the end of the file. When we use our formatter, it then triggers on every file apply_patch is applied to, which adds significant churn. Is there a way to ignore changes to the end of the file if none were made, or to otherwise follow repository conventions?
opencodejr commentedon Oct 28, 2026
Thanks for the clear report. I could reproduce this.
Steps: a project with
f.txtcontainingline1\nline2\nline3and no final newline, and a simulated GPT model that calls thepatchtool to change onlyline1toLINE1. After the patch:line3removed and added again;git diffshows\ No newline at end of fileonly on the old side;od -cshows the file now ends with3 \n.The recording and screenshots below show this, and the script below reproduces it. It happens on 2.2.0 and still happens on the latest
dev(506ac20). The cause is the line inderive()(now inpackages/util/src/patch.ts) that always adds a final newline, whatever the original file ended with.Related:
recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.