{"record":{"id":"ce8bbc4724eecbb9","repo":"gitbutlerapp/gitbutler","slug":"the-resolution-for-path-contains-a-conflict-ma","errorCode":null,"errorMessage":"The resolution for \"{path}\" contains a conflict marker ({marker:?})","messagePattern":"The resolution for \"(.+?)\" contains a conflict marker \\((.+?)\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/resolve/apply.rs","lineNumber":157,"sourceCode":"            .is_some()\n        {\n            bail!(\n                \"Two conflicted paths normalize to the same value ({:?}); resolve this commit manually instead\",\n                normalize_path(&file.path)\n            );\n        }\n    }\n    Ok(files_by_path)\n}\n\n/// Reject content that contains a conflict-marker-shaped line.\npub(crate) fn ensure_no_markers(content: &str, path: &str) -> anyhow::Result<()> {\n    if let Some(marker) = content\n        .lines()\n        .map(|line| line.strip_suffix('\\r').unwrap_or(line))\n        .find(|line| is_marker_shaped(line))\n    {\n        bail!(\"The resolution for \\\"{path}\\\" contains a conflict marker ({marker:?})\");\n    }\n    Ok(())\n}\n\n/// Normalize a path for comparison: trim, backslashes to slashes, strip a\n/// leading `./`, collapse duplicate slashes. Applied to both request and\n/// caller-provided paths, so callers matching against [`ConflictedFile`] paths\n/// should normalize with this too.\n///\n/// [`ConflictedFile`]: super::ConflictedFile\npub fn normalize_path(path: &str) -> String {\n    let mut normalized = path.trim().replace('\\\\', \"/\");\n    while normalized.contains(\"//\") {\n        normalized = normalized.replace(\"//\", \"/\");\n    }\n    normalized\n        .strip_prefix(\"./\")\n        .map(str::to_owned)","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/resolve/apply.rs#L139-L175","documentation":"ensure_no_markers() inspects every line of a HunkResolution::Content payload and rejects content containing a conflict-marker-shaped line (<<<<<<<, =======, >>>>>>> style, CRLF tolerated). Splicing marker-shaped content back into the ours/theirs trees would recreate a conflict inside the 'resolved' commit and corrupt the tree synthesis, so validation fails before anything is written.","triggerScenarios":"Submitting resolve_commit_conflict_hunks with resolution content that still contains the original conflict block - typically an AI/model output that echoed the markers, or a user pasting the whole conflicted file (markers included) as the resolution.","commonSituations":"LLM resolutions that copy the <<<<<<< ours ... ======= ... >>>>>>> scaffold verbatim; hand-pasted merges where only the inner half was meant; files that legitimately start a line with '=======' (README section underlines) getting caught as marker-shaped.","solutions":["Strip the outer marker lines and keep only the resolved content per hunk","If the marker-like line is genuine content (e.g. a '=======' heading), indent it or prefix it so the line no longer starts marker-shaped","Re-submit; validation is atomic so the previous attempt wrote nothing"],"exampleFix":"// before: content still carries the conflict scaffold\n\"<<<<<<< ours\\nkeep this\\n=======\\nand this\\n>>>>>>> theirs\"\n\n// after: only the merged result\n\"keep this\\nand this\"","handlingStrategy":"validation","validationCode":"// Reject marker-shaped lines client-side before submitting content specs\nconst MARKER_RE = /^(<{7}|={7}|>{7})/;\nfunction isMarkerFree(content: string): boolean {\n  return !content.split('\\n').some(line => MARKER_RE.test(line.replace(/\\r$/, '')));\n}\nconst safeSpecs = specs.filter(s => s.resolution.type !== 'content' || isMarkerFree(s.resolution.content));","typeGuard":"function isResolvableContent(content: string): boolean {\n  return isMarkerFree(content); // false => will be rejected by ensure_no_markers\n}","tryCatchPattern":null,"preventionTips":["When splicing model output or user pastes, strip the outer <<<<<<< / ======= / >>>>>>> scaffold before submission","If a '=======' heading is genuine content, indent or prefix the line so it is not marker-shaped","Remember validation is atomic: a rejected attempt wrote nothing, so fixing and resubmitting is safe"],"tags":["conflict-resolution","conflict-markers","content-validation","resolve-api"],"backgroundTag":"conflict-markers-in-content","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}