{"record":{"id":"c9f4652555102807","repo":"can1357/oh-my-pi","slug":"bulk-directive-lists-conflict-id-twice-each","errorCode":null,"errorMessage":"Bulk directive lists conflict #${id} twice — each id may appear once.","messagePattern":"Bulk directive lists conflict #(.+?) twice — each id may appear once\\.","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/write.ts","lineNumber":254,"sourceCode":" * block and still reported success. Per-id bulk is token-only; literal or\n * multi-line replacements must go through individual `conflict://<N>` writes.\n */\nfunction parseBulkDirectives(content: string): Map<number, string> | null {\n\tconst map = new Map<number, string>();\n\tconst stray: string[] = [];\n\tlet sawDirective = false;\n\tfor (const raw of content.split(\"\\n\")) {\n\t\tconst line = raw.trim();\n\t\tif (line.length === 0) continue;\n\t\tconst match = line.match(BULK_DIRECTIVE_RE);\n\t\tif (!match) {\n\t\t\tstray.push(line);\n\t\t\tcontinue;\n\t\t}\n\t\tsawDirective = true;\n\t\tconst id = Number.parseInt(match[1], 10);\n\t\tif (map.has(id)) {\n\t\t\tthrow new ToolError(`Bulk directive lists conflict #${id} twice — each id may appear once.`);\n\t\t}\n\t\tmap.set(id, match[2]);\n\t}\n\t// No directive lines at all → not a per-id block; caller uses uniform mode.\n\tif (!sawDirective) return null;\n\tif (stray.length > 0) {\n\t\tconst sample = stray[0]!;\n\t\tconst tokenHint = BULK_DIRECTIVE_HEAD_RE.test(sample)\n\t\t\t? `Per-id bulk only accepts the tokens @ours/@theirs/@base/@both — one side per id, single line. `\n\t\t\t: \"\";\n\t\tthrow new ToolError(\n\t\t\t`Malformed \\`conflict://*\\` per-id block: ${stray.length} line(s) are not \\`<id>: @side\\` directives (first: \\`${truncateDirectiveLine(sample)}\\`). ` +\n\t\t\t\ttokenHint +\n\t\t\t\t`Literal or multi-line replacement content isn't supported in a per-id block — resolve those blocks with individual \\`write({ path: \"conflict://<N>\", content })\\` calls (you can issue several at once). ` +\n\t\t\t\t`For a pure pick-a-side pass, make every non-empty line \\`<id>: @ours\\` (or @theirs/@base/@both).`,\n\t\t);\n\t}\n\treturn map;","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/write.ts#L236-L272","documentation":"Inside a `conflict://*` bulk-resolution block, each conflict id may carry exactly one `<id>: @side` directive. The parser throws when the same id appears in two directive lines, because a conflict can only be resolved to one side per pass.","triggerScenarios":"A per-id bulk block passed to write targeting conflict://* that contains duplicate lines such as '3: @ours' appearing twice for the same id.","commonSituations":"Hand-assembled or model-generated bulk resolution blocks where a line was duplicated while editing sides.","solutions":["Remove the duplicate directive line so each id appears once","Decide one side per conflict and keep only the intended '@ours'/'@theirs'/'@base'/'@both' line"],"exampleFix":"// before\n\"1: @ours\\n2: @theirs\\n2: @ours\"\n// after\n\"1: @ours\\n2: @theirs\"","handlingStrategy":"validation","validationCode":"function assertUniqueIds(block: string): void {\n  const seen = new Set<number>();\n  for (const line of block.split(\"\\n\")) {\n    const m = line.match(/^\\s*(\\d+):\\s*@(ours|theirs|base|both)\\s*$/);\n    if (!m) continue;\n    const id = Number(m[1]);\n    if (seen.has(id)) throw new Error(`duplicate conflict id ${id}`);\n    seen.add(id);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await write({ path: \"conflict://*\", content: block });\n} catch (e) {\n  if (e instanceof ToolError && e.message.includes(\"twice\")) {\n    const id = Number(e.message.match(/#(\\d+)/)?.[1]);\n    block = dedupeDirective(block, id);\n    return write({ path: \"conflict://*\", content: block });\n  }\n  throw e;\n}","preventionTips":["Build bulk blocks programmatically from a Map keyed by id (dedupes automatically)","Never hand-concatenate directive lines","Deduplicate ids before emitting <id>: @side lines"],"tags":["conflict-resolution","bulk-directives","duplicate-id"],"backgroundTag":"duplicate-directive-id","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}