Hmbown/CodeWhale · error
Complete PR review plan found
Error message
Complete PR review plan found {} file patches; expected {} What it means
After splitting the diff into per-file patches, plan_pr_review verifies the count matches the PR's changed_files count from the GitHub view and that it is non-empty. A mismatch means the diff and PR metadata disagree or the diff parser missed files.
Solutions
- Re-fetch both the PR view and diff so they come from the same revision
- Check the diff is complete/untruncated (compare byte counts, no `gh` output truncation)
- Add a parser test for the diff shape (renames, binary files, new files) that miscounts patches
- Retry — a transient gh failure can produce a partial diff
Example fix
// before let diff = fetch_cached_diff(pr)?; // may be stale // after let (view, diff) = fetch_view_and_diff_together(pr)?; // same revision
Defensive patterns
Strategy: retry
Validate before calling
// sanity check before planning
if diff.is_empty() || view.changed_files == 0 { bail!("empty diff or metadata"); } Try / catch
match plan_pr_review(...) { Err(e) if e.to_string().contains("expected") => refetch_and_retry(pr).await, ... } Prevention
- Fetch PR view and diff from the same revision in one operation
- Verify gh output is untruncated (large PRs)
- Add parser coverage for renames, binary and new files
When it happens
Trigger: The `gh pr diff` output is truncated or partial (network error, huge PR); diff format changed so pr_file_patches misparses file boundaries; diff was cached from an older revision than view.changed_files; changed_files metadata reports 0 or a stale count.
Common situations: Very large PRs where gh truncates output; reviewing a PR whose head moved between metadata fetch and diff fetch; parser regression after a git diff format change (e.g. rename with mode change).
Related errors
- PR review plan did not partition the complete diff…
- cannot parse exactly one Rust TRUSTED_KEYS table
- Cargo metadata is not valid JSON
- Codewhale stream-json line
- Codewhale stream-json line
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/b33b64a4ae05f707.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/review.rs:437
/// skipped in diff order and named in `manifest.skipped_files` (AC4). Only a
/// plan that covers nothing still errors.
///
/// Known limitations, beside the behaviour: skips are whole files — a file
/// with one oversized hunk is skipped entirely, never truncated — and files
/// stay in diff order rather than re-sorted by estimated risk.
pub(crate) fn plan_pr_review(
diff: &str,
view: &super::review_pr::GhPullRequest,
max_chars: usize,
max_passes: usize,
) -> anyhow::Result<PrReviewPlan> {
anyhow::ensure!(max_chars > 0, "Review max_chars must be positive");
anyhow::ensure!(
(1..=MAX_REVIEW_PASSES).contains(&max_passes),
"Review max_passes must be from 1 to {MAX_REVIEW_PASSES}"
);
let patches = pr_file_patches(diff);
anyhow::ensure!(
patches.len() == view.changed_files && !patches.is_empty(),
"Complete PR review plan found {} file patches; expected {}",
patches.len(),
view.changed_files
);
// A whole file stays together whenever it fits. An oversized text file
// splits only at complete hunk boundaries, with the full file header
// replayed into every part so each part stays a self-describing patch;
// no line is elided, shortened or reordered. Sizes use the model
// representation, so a binary payload already omitted there can never
// drive a split.
let mut atoms: Vec<PrReviewAtom<'_>> = Vec::new();
for patch in patches {
let patch_chars = super::review_pr::model_diff(patch).chars().count();
if patch_chars <= max_chars {
atoms.push(PrReviewAtom::Piece(PrReviewPiece {
diff: Cow::Borrowed(patch),View on GitHub (pinned to 73e0f67d83)