{"record":{"id":"f2025c25fbc3b294","repo":"Hmbown/CodeWhale","slug":"patch-removal-mismatch-in-expected","errorCode":null,"errorMessage":"patch removal mismatch in {}: expected '{}'","messagePattern":"patch removal mismatch in (.+?): expected '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/eval.rs","lineNumber":730,"sourceCode":"\n        match kind {\n            \" \" => {\n                let Some(found) = file_lines[cursor..]\n                    .iter()\n                    .position(|line| line == &content)\n                    .map(|offset| cursor + offset)\n                else {\n                    return Err(anyhow!(\n                        \"patch context not found in {}: {}\",\n                        file_path.display(),\n                        content\n                    ));\n                };\n                cursor = found + 1;\n            }\n            \"-\" => {\n                if cursor >= file_lines.len() || file_lines[cursor] != content {\n                    return Err(anyhow!(\n                        \"patch removal mismatch in {}: expected '{}'\",\n                        file_path.display(),\n                        content\n                    ));\n                }\n                file_lines.remove(cursor);\n            }\n            \"+\" => {\n                file_lines.insert(cursor, content);\n                cursor += 1;\n            }\n            _ => return Err(anyhow!(\"unsupported patch line: {raw_line}\")),\n        }\n    }\n\n    let mut updated = file_lines.join(\"\\n\");\n    if had_trailing_newline {\n        updated.push('\\n');","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/eval.rs#L712-L748","documentation":"A removal line (`-content`) must equal the file line at the current cursor exactly, and the cursor must be in bounds (eval.rs:730). A mismatch means the file no longer contains the expected line at that position, so the patch aborts before writing.","triggerScenarios":"The line to delete was already changed or removed; preceding context or removal lines desynchronized the cursor; whitespace differs between the `-` line and the file.","commonSituations":"Same drift causes as context-not-found: concurrent edits, stale file snapshots, line-ending differences.","solutions":["Regenerate the patch against the file's current content","Verify every `-` line matches current file content exactly before applying","Apply one patch at a time, re-reading between attempts"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"let original: Vec<&str> = std::fs::read_to_string(&file_path)?.lines().collect();\nfor removal in patch_removal_lines(&patch) {\n    anyhow::ensure!(\n        original.iter().any(|l| *l == removal),\n        \"removal target not in file: {removal}\"\n    );\n}","typeGuard":null,"tryCatchPattern":"match apply_patch(&root, &patch) {\n    Err(err) if err.to_string().contains(\"patch removal mismatch\") => {\n        let fresh = regenerate_patch_against_current_file(&file_path, &edit)?;\n        apply_patch(&root, &fresh)?; // retry with fresh context\n    }\n    other => other?,\n}","preventionTips":["Never apply patches computed from stale reads","Lock the file or serialize edits so content cannot drift mid-patch","Match whitespace exactly when constructing `-` lines"],"tags":["patch","stale-state","eval","filesystem"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}