{"record":{"id":"952a065077d32103","repo":"can1357/oh-my-pi","slug":"conflict-entry-id-has-no-base-section-2-way-m","errorCode":null,"errorMessage":"Conflict #${entry.id} has no base section (2-way merge). `@base` is only valid for diff3 conflicts.","messagePattern":"Conflict #(.+?) has no base section \\(2-way merge\\)\\. `@base` is only valid for diff3 conflicts\\.","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/conflict-detect.ts","lineNumber":568,"sourceCode":" * - `@base`    → expands to `baseLines`; throws if no base section was\n *               recorded (i.e. the conflict was 2-way, not diff3).\n * - `@both`    → expands to `oursLines` then `theirsLines`.\n */\nexport function expandContentTokens(content: string, entry: ConflictEntry): string {\n\tconst inputLines = content.split(\"\\n\");\n\tconst out: string[] = [];\n\tfor (const rawLine of inputLines) {\n\t\tconst line = rawLine.endsWith(\"\\r\") ? rawLine.slice(0, -1) : rawLine;\n\t\tswitch (line) {\n\t\t\tcase \"@ours\":\n\t\t\t\tout.push(...entry.oursLines);\n\t\t\t\tbreak;\n\t\t\tcase \"@theirs\":\n\t\t\t\tout.push(...entry.theirsLines);\n\t\t\t\tbreak;\n\t\t\tcase \"@base\":\n\t\t\t\tif (!entry.baseLines) {\n\t\t\t\t\tthrow new ToolError(\n\t\t\t\t\t\t`Conflict #${entry.id} has no base section (2-way merge). \\`@base\\` is only valid for diff3 conflicts.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tout.push(...entry.baseLines);\n\t\t\t\tbreak;\n\t\t\tcase \"@both\":\n\t\t\t\tout.push(...entry.oursLines, ...entry.theirsLines);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tout.push(rawLine);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn out.join(\"\\n\");\n}\n\n/** Reconstruct a conflict-marker line from prefix and optional label. */\nfunction markerLine(prefix: string, label: string | undefined): string {","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/conflict-detect.ts#L550-L586","documentation":"expandContentTokens throws when the @base token is used in replacement content for a conflict that has no base section. Two-way (non-diff3) merges record only ours/theirs sides; @base only exists for diff3-style conflicts, so expanding @base to nothing would silently corrupt the resolution and the tool refuses instead.","triggerScenarios":"Writing content containing '@base' (e.g. via conflict://<id> or conflict://*) against a conflict registered from a 2-way merge (merge.conflictStyle diff, not diff3/zdiff3); a generic @ours/@theirs/@base template applied to all conflicts where some are 2-way.","commonSituations":"Repo git config switched from diff3 to plain merge style (or was never diff3) while tooling assumes diff3; bulk wildcard writes with @base hitting a mix of conflict styles; agents copying resolution templates that assume diff3.","solutions":["Remove the @base token and resolve using @ours/@theirs/@both, or paste the intended base content explicitly.","Re-register conflicts with diff3 style (git config merge.conflictStyle diff3, re-trigger the merge) if a true base is needed.","Use the conflict's ours/theirs sides as a stand-in for base when the ancestor version isn't available."],"exampleFix":"// before\nwrite({ path: 'conflict://2', content: '@base' }); // 2-way conflict\n// after\nwrite({ path: 'conflict://2', content: '@theirs' }); // no base side exists","handlingStrategy":"validation","validationCode":"if (content.includes('@base') && entry.baseLines === undefined) {\n  throw new Error(`conflict #${entry.id} is 2-way; @base unavailable`);\n}","typeGuard":"function hasBase(entry) {\n  return entry.baseLines !== undefined;\n}","tryCatchPattern":"try {\n  await write({ path: `conflict://${id}`, content });\n} catch (err) {\n  if (String(err?.message).includes('has no base section')) {\n    await write({ path: `conflict://${id}`, content: content.replaceAll('@base', '@ours') });\n  } else throw err;\n}","preventionTips":["Detect conflict style (baseLines presence) before using @base in templates.","Don't assume diff3; repos often run with plain merge style.","Keep @base only in templates gated on diff3 availability.","For bulk wildcard writes, use @base-free content unless all conflicts are diff3."],"tags":["conflict-resolution","merge-conflict","diff3","validation"],"backgroundTag":"missing-base-section","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}