Hmbown/CodeWhale · error

Model response incomplete: provider stop reason `{}`; the JS

Error message

Model response incomplete: provider stop reason `{}`; the JSON receipt records success=false.

What it means

JSON-mode variant of the incomplete-stop-reason guard: the one-shot run first prints a JSON receipt (which records success=false and the stop reason), then bails with this message for the same incomplete reasons: output limits (length, max_tokens, max_output_tokens), content_filter, model_context_window_exceeded, or 'incomplete:'-prefixed Responses API statuses.

Source

Thrown at crates/tui/src/lib.rs:10101

    let usage = response.usage.clone();
    let mut output = String::new();
    for block in response.content {
        if let ContentBlock::Text { text, .. } = block {
            output.push_str(&text);
        }
    }
    println!(
        "{}",
        serde_json::to_string_pretty(&one_shot_exec_json_receipt(
            provider,
            model,
            output,
            stop_reason.clone(),
            usage,
        ))?
    );
    if is_incomplete_stop_reason(stop_reason.as_deref()) {
        anyhow::bail!(
            "Model response incomplete: provider stop reason `{}`; the JSON receipt records success=false.",
            stop_reason_detail(stop_reason.as_deref())
        );
    }
    Ok(())
}

fn one_shot_exec_json_receipt(
    provider: String,
    model: String,
    output: String,
    stop_reason: Option<String>,
    usage: crate::models::Usage,
) -> serde_json::Value {
    let incomplete = crate::models::is_incomplete_stop_reason(stop_reason.as_deref());
    let error = incomplete.then(|| {
        format!(
            "Model response incomplete: provider stop reason `{}`.",

View on GitHub (pinned to 8880682c63)

Solutions

  1. Read the receipt's stop_reason field and fix the named cause (raise the output budget, shrink input, or change model)
  2. Check the receipt's success flag rather than assuming printed JSON means the command worked
  3. Split oversized tasks into smaller one-shot calls so answers fit the budget
  4. For content_filter stops, adjust the prompt or policy instead of retrying

Example fix

# before: receipt printed, exit code ignored
out=$(sandbox exec --json 'summarize this 50k-line log')
# after: branch on the receipt, then the exit code
out=$(sandbox exec --json 'summarize this 50k-line log') || echo "incomplete: $out" >&2
Defensive patterns

Strategy: type-guard

Type guard

// The receipt is structured output: branch on its fields, not on stderr text
#[derive(serde::Deserialize)]
struct OneShotReceipt {
    success: bool,
    stop_reason: Option<String>,
}
fn failed_by_stop_reason(raw: &str) -> Option<String> {
    serde_json::from_str::<OneShotReceipt>(raw)
        .ok()
        .filter(|r| !r.success)
        .and_then(|r| r.stop_reason)
}

Try / catch

// Script pattern: parse the receipt from stdout, then honor the exit code
const out = runOneShotJson(prompt);
const receipt = JSON.parse(out);
if (receipt.success === false && /length|max_tokens|content_filter/.test(receipt.stop_reason ?? '')) {
    return retryWithHigherBudget(prompt);
}

Prevention

When it happens

Trigger: One-shot runs with JSON output enabled where the answer exceeds the output token limit, the context window is exceeded, or a content filter stops generation; the receipt on stdout is valid JSON, but the process exit code is non-zero.

Common situations: Automation parsing receipts hitting silent truncation, structured pipelines assuming receipt presence implies success, low token defaults in CI-invoked one-shot runs.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/5a84549c2ed2594a. Report an issue: GitHub.