Hmbown/CodeWhale · error

Only / review passes completed; the partial review was not…

Error message

Only {}/{} review passes completed; the partial review was not accepted or posted.

What it means

`ReviewAggregation::finish` guards the PR review pipeline against posting a partial review. Before merging per-pass outputs into a `ReviewOutput`, it asserts that the number of collected pass outputs equals the number of passes declared in the manifest; if any pass was skipped, failed, or returned early, the review is rejected instead of being accepted or posted with incomplete coverage.

Solutions

  1. Inspect the logs for the failed/skipped review pass and fix its root cause, then re-run the review
  2. Ensure every planned pass's output is pushed to the aggregator (including defensive pushes on error paths) before calling `finish`
  3. Re-run the whole review from scratch so all manifest passes complete

Example fix

// before
if outputs.len() < manifest.passes.len() { finish(outputs.as_slice(), &complete_diff)?; }
// after
anyhow::ensure!(outputs.len() == manifest.passes.len(), "missing review pass outputs");
let (review, diff, coverage) = finish(outputs, &complete_diff)?;
Defensive patterns

Strategy: validation

Validate before calling

if aggregator.outputs.len() != aggregator.manifest.passes.len() { return Err(anyhow!("review incomplete: {}/{} passes", aggregator.outputs.len(), aggregator.manifest.passes.len())); }

Try / catch

match aggregator.finish(&complete_diff) { Ok((review, diff, coverage)) => post(review), Err(e) => { log::error!("review rejected: {e}"); restart_full_review(); } }

Prevention

When it happens

Trigger: Calling `finish(complete_diff)` on an aggregator whose `outputs` vec has fewer entries than `manifest.passes.len()` — e.g. a review pass errored, was skipped due to a missing diff for its slice, or an agent loop dropped one of the planned passes.

Common situations: A subagent pass timed out or panicked and its output was not pushed; a manifest was built for N passes but only N-1 succeeded and the code called `finish` anyway; partial-result handling drifted after a refactor of the pass loop.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/5c3199ec7578cd5b. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/review.rs:724

                && self.manifest.passes.get(expected - 1) == Some(&pass.manifest),
            "Review pass arrived out of order or does not match the immutable manifest; expected pass {expected}"
        );
        let output = ReviewOutput::from_structured_str(&raw).ok_or_else(|| {
            anyhow::anyhow!(
                "Review pass {expected}/{} did not return valid structured JSON; the partial review was not accepted or posted.",
                self.manifest.passes.len()
            )
        })?;
        self.outputs.push(output);
        self.raw_outputs.push(raw);
        Ok(())
    }

    pub(crate) fn finish(
        self,
        complete_diff: &str,
    ) -> anyhow::Result<(ReviewOutput, String, ReviewReceiptCoverage)> {
        anyhow::ensure!(
            self.outputs.len() == self.manifest.passes.len(),
            "Only {}/{} review passes completed; the partial review was not accepted or posted.",
            self.outputs.len(),
            self.manifest.passes.len()
        );
        anyhow::ensure!(
            diff_fingerprint(complete_diff) == self.manifest.diff_fingerprint,
            "Complete PR diff fingerprint changed before review aggregation"
        );
        let mut issues = Vec::new();
        let mut suggestions = Vec::new();
        let mut summaries = Vec::new();
        let mut assessments = Vec::new();
        for (index, output) in self.outputs.into_iter().enumerate() {
            if !output.summary.is_empty() {
                summaries.push(format!("Pass {}: {}", index + 1, output.summary));
            }
            if !output.overall_assessment.is_empty() {

View on GitHub (pinned to 73e0f67d83)