{"record":{"id":"3c0496db60184208","repo":"Hmbown/CodeWhale","slug":"incomplete-pr-diff-a-text-hunk-is-truncated-or-malformed","errorCode":null,"errorMessage":"Incomplete PR diff: a text hunk is truncated or malformed","messagePattern":"Incomplete PR diff: a text hunk is truncated or malformed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/review_pr.rs","lineNumber":191,"sourceCode":"    let mut has_patch = false;\n    let mut has_full_index = false;\n    for line in diff.lines() {\n        if remaining != (0, 0) {\n            match line.as_bytes().first() {\n                Some(b'+') if remaining.1 > 0 => {\n                    remaining.1 -= 1;\n                    additions += 1;\n                }\n                Some(b'-') if remaining.0 > 0 => {\n                    remaining.0 -= 1;\n                    deletions += 1;\n                }\n                Some(b' ') if remaining.0 > 0 && remaining.1 > 0 => {\n                    remaining.0 -= 1;\n                    remaining.1 -= 1;\n                }\n                Some(b'\\\\') => {}\n                _ => bail!(\"Incomplete PR diff: a text hunk is truncated or malformed\"),\n            }\n            continue;\n        }\n        if line.starts_with(\"diff --git \") {\n            if files > 0 && !has_patch {\n                bail!(\"Incomplete PR diff: a file patch is missing\");\n            }\n            files += 1;\n            has_patch = false;\n            has_full_index = false;\n        } else if line.starts_with(\"index \") {\n            has_full_index = full_index_objects(line);\n        } else if let Some((_, old, new)) = super::review_hunks::parse_hunk_header(line) {\n            remaining = (old, new);\n            has_patch = true;\n        } else if line.starts_with(\"@@\") {\n            bail!(\"Incomplete PR diff: malformed hunk header\");\n        } else if [","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/review_pr.rs#L173-L209","documentation":"complete_file_set walks the fetched `git diff` line by line, tracking how many hunk lines remain per file. When a hunk ends with fewer remaining context/addition/deletion lines than the header promised — or contains a line the state machine does not recognize — the diff is truncated or malformed and the review is rejected rather than performed on partial content.","triggerScenarios":"The diff text emitted by `git diff` was cut off (output limit, killed process, corrupted pipe) or a hunk body has fewer lines than the @@ -a,b +c,d @@ header counts, leaving the line matcher at a non-continuation token.","commonSituations":"Hitting the bounded stdout read cap on very large diffs; a pager or filter mangling output (missing --no-ext-diff equivalent); tools post-processing the diff text and dropping lines; copying diffs through processes that trim trailing context.","solutions":["Re-fetch the diff (`gh pr diff`/`git diff` path in fetch_diff) and confirm the byte count matches the PR's additions+deletions plus headers","Remove any pager/filter wrappers between git and the tool (`GIT_PAGER=cat`, `core.pager=cat`, no external diff drivers)","Verify no output truncation happened (check the 64KiB bounded readers in run_command and any size limits); re-run the review on the complete diff"],"exampleFix":"// before: piping diff through a pager/mangler\ngit diff base...head | less\n// after: plain, no-ext-diff, no pager\ngit diff --no-ext-diff --no-color base...head","handlingStrategy":"validation","validationCode":"// verify hunk line counts before review\nfor hunk in diff.lines().filter(|l| l.starts_with(\"@@\")) {\n    let (_, old, new) = parse_hunk_header(hunk).ok_or(\"bad header\")?;\n    // count following +/ -/space lines and compare to old/new\n}","typeGuard":null,"tryCatchPattern":"match diff_with(&view) {\n    Err(e) if e.to_string().contains(\"truncated or malformed\") => eprintln!(\"diff incomplete; refetch with GIT_PAGER=cat git diff --no-ext-diff\"),\n    other => other?,\n}","preventionTips":["Fetch diffs without pagers, colors, or post-processing filters","Keep diff output under any size caps or raise them for large PRs","Never reflow or line-wrap diff text before feeding it to the tool"],"tags":["git","diff","data-integrity","truncation"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}