vxcontrol/pentagi · error
%d of %d hunk(s) could not be applied - read the file again
Error message
%d of %d hunk(s) could not be applied - read the file again and retry with context that matches its current content exactly: %s
What it means
diff-match-patch applied the patch, but one or more hunks did not find their context in the current file content. The error lists which hunk headers failed and a preview of the text each hunk expected to find, instructing the caller to re-read the file and retry with exact context. This is the expected failure mode for diffs built against a stale version of the file.
Source
Thrown at backend/pkg/tools/file_diff.go:315
patchText := buildGoDiffPatchText(hunks, content)
dmp := diffmatchpatch.New()
patches, err := dmp.PatchFromText(patchText)
if err != nil {
return "", 0, fmt.Errorf("internal error building patch: %w", err)
}
newContent, applied := dmp.PatchApply(patches, content)
var failed []string
for i, ok := range applied {
if !ok && i < len(hunks) {
failed = append(failed, fmt.Sprintf("%s (not found in the file, looked for: %q)", hunks[i].header, hunkOldPreview(hunks[i])))
}
}
if len(failed) > 0 {
return "", 0, fmt.Errorf(
"%d of %d hunk(s) could not be applied - read the file again and retry with context that matches its current content exactly:\n%s",
len(failed), len(hunks), strings.Join(failed, "\n"),
)
}
return newContent, len(hunks), nil
}
View on GitHub (pinned to ea665308ba)
Solutions
- Re-read the file from disk and regenerate the diff using its current exact content as context.
- Copy context lines verbatim from the file, including trailing whitespace, instead of retyping them.
- Reduce the amount of context to the minimum needed to be unique, lessening the chance of mismatch.
- Normalize line endings (match the file's CRLF/LF convention) before applying.
- Retry after confirming no other process is concurrently modifying the file.
Example fix
// before: context invented by the model "@@ -3,2 +3,3 @@\n some old line\n+added" // after: context copied exactly from a fresh file read "@@ -3,2 +3,3 @@\n someOldLine := compute(x) // exact current line\n+added"
Defensive patterns
Strategy: retry
Validate before calling
func contextMatches(content, ctxLine string) bool {
return strings.Contains(content, strings.TrimPrefix(ctxLine, " "))
}
// verify every context/removal line appears in freshly read content before applying Try / catch
for attempt := 0; attempt < 3; attempt++ {
content, _ := readFile(path) // fresh read each attempt
diff := buildDiffAgainst(content)
newContent, _, err := ApplyUnifiedDiff(ctx, path, diff)
if err == nil { return newContent, nil }
if !strings.Contains(err.Error(), "could not be applied") { return err }
} Prevention
- Always build diffs from a file read in the same session — never from cached or remembered content
- Copy context lines verbatim including trailing whitespace
- Minimize context lines to what is needed for uniqueness
- Match the file's line-ending convention (CRLF vs LF)
- Avoid concurrent writers to the same file while diffing
When it happens
Trigger: EditFile/ApplyUnifiedDiff called with a diff whose context lines do not byte-match the file's current content — file changed since the diff was made, line numbers drifted, trailing whitespace or line endings differ, or context was paraphrased by an LLM instead of copied.
Common situations: Concurrent edits between reading the file and applying the diff; agent generated context from memory rather than an actual file read; CRLF vs LF mismatch; context lines abbreviated with '...' or re-wrapped by chat rendering.
Related errors
- Token.InvalidRequest
- edit_file was called but did not produce the requested chang
- FlowFiles.AlreadyExists
- %w: destination %q is a file; cannot move multiple sources i
- %w: resource %q already exists and is not a directory
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/58d2aefbc6669295.
Report an issue: GitHub.