{"record":{"id":"1553b014db084beb","repo":"can1357/oh-my-pi","slug":"multiple-hashline-sections-resolve-to-the-same-fil","errorCode":null,"errorMessage":"Multiple hashline sections resolve to the same file (${previous} and ${entry.section.path}). Merge their ops under one header before applying.","messagePattern":"Multiple hashline sections resolve to the same file \\((.+?) and (.+?)\\)\\. Merge their ops under one header before applying\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/hashline/execute.ts","lineNumber":96,"sourceCode":" * (issue #2081 saw 182 byte-identical no-op results in 205 calls before the\n * user aborted).\n */\nfunction noChangeLoopDiagnostic(path: string, count: number): string {\n\treturn (\n\t\t`STOP. Edits to ${path} have been a byte-identical no-op ${count} times in a row — ` +\n\t\t`the patch body matches the file at the targeted lines and the soft hint did not break the cycle. ` +\n\t\t`Cease re-issuing this payload. Either the intended change is already on disk (move on), ` +\n\t\t`or your anchor is wrong (re-read the file with \\`read\\` to observe the current line numbers and ` +\n\t\t`tag, then author a different edit). This exact payload will keep being rejected until it changes.`\n\t);\n}\n\nfunction assertUniqueCanonicalPaths(prepared: readonly PreparedSection[]): void {\n\tconst seen = new Map<string, string>();\n\tfor (const entry of prepared) {\n\t\tconst previous = seen.get(entry.canonicalPath);\n\t\tif (previous !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Multiple hashline sections resolve to the same file (${previous} and ${entry.section.path}). Merge their ops under one header before applying.`,\n\t\t\t);\n\t\t}\n\t\tseen.set(entry.canonicalPath, entry.section.path);\n\t}\n}\n\nfunction narrowBatchRequest(outer: LspBatchRequest | undefined, isLast: boolean): LspBatchRequest | undefined {\n\tif (!outer) return undefined;\n\treturn { id: outer.id, flush: isLast && outer.flush };\n}\n\ninterface RenderedSection {\n\ttoolResult: AgentToolResult<EditToolDetails, typeof hashlineEditParamsSchema>;\n\tperFileResult: EditToolPerFileResult;\n}\n\nasync function observeAppliedSection(","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/hashline/execute.ts#L78-L114","documentation":"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.","triggerScenarios":"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.","commonSituations":"Agents batching multi-file edits and accidentally repeating a file; path aliasing via './' prefix, trailing segments, or case differences on case-insensitive filesystems.","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."],"exampleFix":"// before (two headers, same file)\n@@@ src/a.ts:1a2b\n- foo\n\n@@@ src/a.ts:1a2b\n- bar\n+ baz\n// after (merged)\n@@@ src/a.ts:1a2b\n- foo\n- bar\n+ baz","handlingStrategy":"validation","validationCode":"import * as path from 'node:path';\nconst seen = new Set<string>();\nfor (const s of sections) {\n  const canon = path.resolve(session.cwd, s.path);\n  if (seen.has(canon)) throw new Error(`Duplicate section for ${canon}`);\n  seen.add(canon);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await executeHashlineSingle(options);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('resolve to the same file')) {\n    return await executeHashlineSingle(mergeSectionsForSameFile(options.input));\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["hashline","duplicate-section","validation","edit-tool"],"backgroundTag":"duplicate-file-section","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}