can1357/oh-my-pi · error · ApplyPatchError
Diff contains ${multiFileCount} file markers. Single-file pa
Error message
Diff contains ${multiFileCount} file markers. Single-file patches cannot contain multi-file markers. What it means
parseDiffHunks is the single-file patch parser: it counts multi-file markers (e.g. '*** Update File:' / git 'diff --git' style headers) in the input and throws ApplyPatchError if more than one is present. Multi-file patches must go through the multi-file parser; feeding them here would silently merge changes intended for different files into one hunk list.
Source
Thrown at packages/coding-agent/src/edit/diff.ts:809
if (!candidate) return undefined;
return candidate.replace(/^(a|b)\//, "");
}
if (line.startsWith("*** Update File:")) {
return line.slice("*** Update File:".length).trim();
}
if (line.startsWith("*** Add File:")) {
return line.slice("*** Add File:".length).trim();
}
if (line.startsWith("*** Delete File:")) {
return line.slice("*** Delete File:".length).trim();
}
return undefined;
}
export function parseDiffHunks(diff: string): DiffHunk[] {
const multiFileCount = countMultiFileMarkers(diff);
if (multiFileCount > 1) {
throw new ApplyPatchError(
`Diff contains ${multiFileCount} file markers. Single-file patches cannot contain multi-file markers.`,
);
}
const normalizedDiff = normalizeDiff(diff);
const lines = normalizedDiff.split("\n");
const hunks: DiffHunk[] = [];
let i = 0;
while (i < lines.length) {
const line = lines[i];
const trimmed = line.trim();
if (trimmed === "") {
i++;
continue;
}
View on GitHub (pinned to 9690622007)
Solutions
- Route the patch to the multi-file parser instead of parseDiffHunks.
- Split the patch on its file markers and call parseDiffHunks once per single-file section.
- If only one file should change, delete the extra file sections from the patch.
- Fix the prompt/tool contract so the model emits one file per patch invocation.
Example fix
// before parseDiffHunks(patchWithTwoFileMarkers) // after for (const section of splitByFileMarkers(patch)) parseDiffHunks(section)
Defensive patterns
Strategy: validation
Validate before calling
const markers = diff.match(/^\*{3} (?:Update|Add|Delete) File:|^diff --git /gm) ?? [];
if (markers.length > 1) {
throw new Error(`Patch contains ${markers.length} files; split it before parseDiffHunks`);
} Try / catch
try {
hunks = parseDiffHunks(diff);
} catch (err) {
if (err instanceof ApplyPatchError && err.message.includes("file markers")) {
// switch to the multi-file parser or split on the markers and parse per file
} else throw err;
} Prevention
- Match the parser to the patch shape: multi-file patches go to the multi-file parser.
- Constrain LLM agents to one file per patch call when using the single-file API.
- Split concatenated diffs on their file markers before parsing each section.
When it happens
Trigger: Calling parseDiffHunks with a patch containing two or more file markers — e.g. a patch updating two files ('*** Update File: a.ts' ... '*** Update File: b.ts') or concatenated git diffs for multiple files.
Common situations: LLM agents emitting a multi-file patch where a single-file one was expected; concatenating several per-file diffs before parsing; choosing the single-file API by mistake when the patch legitimately touches multiple files.
Related errors
- Line numbers in @@ header must be >= 1
- Line hint must be >= 1
- Expected hunk to start with @@ context marker, got: '${lines
- Line numbers must be >= 1 (got ${oldStartLine})
- Line numbers must be >= 1 (got ${newStartLine})
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/90b594a5f21b4e92.
Report an issue: GitHub.