can1357/oh-my-pi · error
Multiple hashline sections resolve to the same file (${previ
Error message
Multiple hashline sections resolve to the same file (${previous} and ${entry.section.path}). Merge their ops under one header before applying. What it means
executeHashlineSingle() prepares all sections from the input, then assertUniqueCanonicalPaths() rejects input where two sections canonicalize (resolve) to the same file on disk. Sequential per-file application would apply the first section and invalidate the second's snapshot, so the library fails fast and instructs merging the ops under a single section header.
Source
Thrown at packages/coding-agent/src/edit/hashline/execute.ts:96
* (issue #2081 saw 182 byte-identical no-op results in 205 calls before the
* user aborted).
*/
function noChangeLoopDiagnostic(path: string, count: number): string {
return (
`STOP. Edits to ${path} have been a byte-identical no-op ${count} times in a row — ` +
`the patch body matches the file at the targeted lines and the soft hint did not break the cycle. ` +
`Cease re-issuing this payload. Either the intended change is already on disk (move on), ` +
`or your anchor is wrong (re-read the file with \`read\` to observe the current line numbers and ` +
`tag, then author a different edit). This exact payload will keep being rejected until it changes.`
);
}
function assertUniqueCanonicalPaths(prepared: readonly PreparedSection[]): void {
const seen = new Map<string, string>();
for (const entry of prepared) {
const previous = seen.get(entry.canonicalPath);
if (previous !== undefined) {
throw new Error(
`Multiple hashline sections resolve to the same file (${previous} and ${entry.section.path}). Merge their ops under one header before applying.`,
);
}
seen.set(entry.canonicalPath, entry.section.path);
}
}
function narrowBatchRequest(outer: LspBatchRequest | undefined, isLast: boolean): LspBatchRequest | undefined {
if (!outer) return undefined;
return { id: outer.id, flush: isLast && outer.flush };
}
interface RenderedSection {
toolResult: AgentToolResult<EditToolDetails, typeof hashlineEditParamsSchema>;
perFileResult: EditToolPerFileResult;
}
async function observeAppliedSection(View on GitHub (pinned to 9690622007)
Solutions
- Merge both sections' ops into a single section under one `@@@ path:tag` header and re-issue one edit.
- Deduplicate the patch input so each file appears once, or split into sequential edit calls (re-reading between them for a fresh tag).
- Check for path normalization mismatches ('./' prefixes, duplicate slashes) making one file look like two.
Example fix
// before (two headers, same file) @@@ src/a.ts:1a2b - foo @@@ src/a.ts:1a2b - bar + baz // after (merged) @@@ src/a.ts:1a2b - foo - bar + baz
Defensive patterns
Strategy: validation
Validate before calling
import * as path from 'node:path';
const seen = new Set<string>();
for (const s of sections) {
const canon = path.resolve(session.cwd, s.path);
if (seen.has(canon)) throw new Error(`Duplicate section for ${canon}`);
seen.add(canon);
} Try / catch
try {
return await executeHashlineSingle(options);
} catch (e) {
if (e instanceof Error && e.message.includes('resolve to the same file')) {
return await executeHashlineSingle(mergeSectionsForSameFile(options.input));
}
throw e;
} Prevention
- Deduplicate sections per canonical path before submitting a multi-file patch.
- Normalize './' prefixes and duplicate slashes in section paths.
- When multiple changes target one file, emit them as ops under a single header.
When it happens
Trigger: A patch containing two sections for the same file — e.g. duplicate headers, two spellings/aliases of one path (./src/a.ts vs src/a.ts), or a model emitting separate fix-up blocks for one file in one edit call.
Common situations: Agents batching multi-file edits and accidentally repeating a file; path aliasing via './' prefix, trailing segments, or case differences on case-insensitive filesystems.
Related errors
- Missing hashline snapshot tag for ${sectionPath}; use `${HL_
- oldText must not be empty.
- Found ${occurrences} occurrences${pathSuffix}${moreMsg}:\n\n
- ${message} || Unable to read ${sectionPath}
- No hashline sections found in input.
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1553b014db084beb.
Report an issue: GitHub.