Hmbown/CodeWhale · error · anyhow::Error

translate: provider response incomplete

Error message

translate: provider response incomplete ({})

What it means

After receiving an Anthropic Messages (or Responses API) reply, the client checks the stop reason with codewhale_models::is_incomplete_stop_reason and errors out if the provider explicitly did not finish: output token limit (length/max_tokens), content_filter, model_context_window_exceeded, or any `incomplete:*` reason. Rather than returning a truncated translation as if it were complete, the client surfaces the provider's stop reason detail in the message.

Solutions

  1. Increase the max output tokens / output budget for the request so generation can finish
  2. Shrink the prompt or conversation history (compact context) to avoid context-window exhaustion
  3. Check whether a content filter applies and rephrase or switch model/provider
  4. Read the detail inside the message (stop_reason_detail) to identify which of length/content_filter/context-window caused it and address that specific cause

Example fix

// before
request.max_tokens = 256; // generation truncated at limit

// after
request.max_tokens = 4096; // enough headroom for the full response
Defensive patterns

Strategy: retry

Validate before calling

// Before sending, check the request fits the output budget:
if request.max_tokens.unwrap_or(0) < 1024 {
    eprintln!("max_tokens is low; Anthropic responses risk finishing with stop_reason=\"max_tokens\"");
}

Try / catch

match result {
    Err(e) if e.to_string().starts_with("translate: provider response incomplete") => {
        let detail = e.to_string(); // e.g. "max_tokens" / "content_filter"
        if detail.contains("max_tokens") || detail.contains("length") {
            // retry once with a larger output budget and compacted context
        } else {
            // surface to user: filter or context-window issue, do not blind-retry
        }
    }
    other => other?,
}

Prevention

When it happens

Trigger: A request whose response carries stop_reason "length"/"max_tokens"/"max_output_tokens" (output cap hit), "content_filter", "model_context_window_exceeded", or an `incomplete:`-prefixed reason, on the Anthropic Messages path in the translate flow (client.rs:2815).

Common situations: Low max_tokens / output budget configured while the model needs more tokens; a provider safety filter truncating output; the conversation exceeding the model context window so generation stops early; a provider introducing a new incomplete stop reason spelled `incomplete:<future-reason>`.

Related errors


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

Appendix: source

Thrown at crates/tui/src/client.rs:2815

            // Non-Chat dialects reuse the prepared-request seam so translation
            // cannot drift from production shaping. Translation is still an
            // *auxiliary* call, not a primary agent turn: the Chat dialect
            // below builds its own small fixed body, and `/preview-request`
            // deliberately does not claim to describe either
            // (see `docs/PREVIEW_REQUEST.md`).
            let prepared = self.prepare_outbound_request(
                translation_message_request(text, model, target_language, max_tokens),
                false,
            )?;
            let response = match prepared.dialect {
                WireDialect::OpenAiResponses => self.handle_responses_message(&prepared).await?,
                WireDialect::AnthropicMessages => self.handle_anthropic_message(&prepared).await?,
                WireDialect::ChatCompletions => unreachable!(),
            };
            let usage = (response.usage != Usage::default()).then_some(response.usage.clone());
            let translated =
                if codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
                    Err(anyhow::anyhow!(
                        "translate: provider response incomplete ({})",
                        codewhale_models::stop_reason_detail(response.stop_reason.as_deref())
                    ))
                } else {
                    translation_text_from_response(&response)
                };
            return Ok(TranslationProviderResponse {
                translated,
                route,
                usage,
            });
        }

        let url = api_url_with_suffix(
            self.chat_transport_base_url(),
            "chat/completions",
            self.path_suffix.as_deref(),
        );

View on GitHub (pinned to 73e0f67d83)