gitbutlerapp/gitbutler · warning · Error
Failed to parse diff header
Error message
Failed to parse diff header
What it means
The agent-cleanup rewrite writes files atomically: read content, write a temp file in the same directory, then rename over the target. Right before persisting, it re-reads the target and compares to the snapshot it based the rewrite on; if they differ (someone wrote in between), it bails instead of silently discarding that edit. A later sweep re-runs on the fresh content, so backing off is safe.
Source
Thrown at packages/ui/src/lib/utils/diffParsing.ts:168
readonly newLines: number;
readonly comment?: string;
readonly contentSections: ContentSection[];
};
type BaseDiffRows = { prevRows: BaseRow[]; nextRows: BaseRow[] };
const headerRegex =
/@@ -(?<beforeStart>\d+),?(?<beforeCount>\d+)? \+(?<afterStart>\d+),?(?<afterCount>\d+)? @@(?<comment>.+)?/;
function parseHeader(header: string): {
oldStart: number;
newStart: number;
oldLines: number;
newLines: number;
comment?: string;
} {
const result = headerRegex.exec(header);
if (!result?.groups) {
throw new Error("Failed to parse diff header");
}
return {
oldStart: parseInt(result.groups["beforeStart"]),
oldLines: parseInt(result.groups["beforeCount"] ?? "1"),
newStart: parseInt(result.groups["afterStart"]),
newLines: parseInt(result.groups["afterCount"] ?? "1"),
comment: result.groups["comment"],
};
}
function lineType(line: string): SectionType {
if (line.startsWith("+")) {
return SectionType.AddedLines;
} else if (line.startsWith("-")) {
return SectionType.RemovedLines;
} else {
return SectionType.Context;
}View on GitHub (pinned to caf1f223d3)
Solutions
- Retry the sweep: re-running the cleanup command re-reads the fresh content and reapplies the rewrite
- Avoid running two rewriting commands over the same file simultaneously; serialize cleanups in your tooling
- If it persists, check for a formatter/watcher that keeps touching the file and pause it during the sweep
Example fix
# shell # before: 'file changed while preparing the rewrite; leaving it alone' but agent cleanup # simply re-run; the sweep is idempotent over fresh content # after: rewrite applies cleanly
Defensive patterns
Strategy: retry
Try / catch
match apply_rewrite(path, new_content) {
Err(err) if err.to_string().contains("changed while preparing") => {
// benign back-off: re-read the file and re-run the sweep on fresh content
}
other => other,
} Prevention
- Re-run the cleanup command; the sweep is idempotent over current content
- Serialize file-rewriting commands (formatters, other agents) instead of racing them
When it happens
Trigger: The managed file (e.g. an AGENTS.md/CLAUDE.md-style file with managed blocks) is modified between the initial read and the rename - another agent, editor autosave, formatter, or concurrent but command writing the same file while the cleanup sweep is in flight.
Common situations: Multiple agents/tools editing instruction files concurrently; IDE autosave or a linter rewriting the file mid-sweep; slow disks enlarging the read-to-rename window.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- When using OpenAI in a bring your own key configuration, you
- Invalid source: expected an uncommitted file or branch
- Could not discard all selected changes: {refused_paths}
- Cannot compute diff specs for worktree `{name}`
- Cannot compute diff specs for stacks
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/b2993c5f03ad1c0e.
Report an issue: GitHub.