Hmbown/CodeWhale · error · anyhow::Error

Antigravity cloud-code accepts text parts only; non-text con

Error message

Antigravity cloud-code accepts text parts only; non-text content fails closed

What it means

The cloud-code builder only accepts text content blocks; any non-text block (image, tool_use, tool_result, etc.) triggers this bail. Empty or whitespace-only text blocks are silently skipped, but a non-text block fails closed with no guessing, because the cloud-code wire format only models text parts. This check sits inside the per-block loop, so it fires on the first offending block.

Source

Thrown at crates/tui/src/client/cloud_code.rs:75

        bail!(
            "Antigravity cloud-code tools are not implemented yet; send a text-only turn or use the google provider"
        );
    }
    let mut contents = Vec::new();
    for message in &request.messages {
        let role = match message.role.as_str() {
            "user" => "user",
            "assistant" | "model" => "model",
            other => bail!("Antigravity cloud-code does not accept role {other:?}"),
        };
        let mut parts = Vec::new();
        for block in &message.content {
            match block {
                ContentBlock::Text { text, .. } if !text.trim().is_empty() => {
                    parts.push(json!({ "text": text }));
                }
                ContentBlock::Text { .. } => {}
                _ => bail!(
                    "Antigravity cloud-code accepts text parts only; non-text content fails closed"
                ),
            }
        }
        if !parts.is_empty() {
            contents.push(json!({ "role": role, "parts": parts }));
        }
    }
    if contents.is_empty() {
        bail!("Antigravity cloud-code request has no text contents");
    }
    let model = request.model.trim();
    if model.is_empty() {
        bail!("Antigravity cloud-code request is missing a model id");
    }
    Ok(json!({
        "model": model,
        "userAgent": "codewhale",

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Remove non-text blocks from the turn before sending on antigravity
  2. Use the `google` provider for multimodal or tool-carrying turns
  3. Flatten tool output into plain text if a text-only summary is acceptable

Example fix

// before
message.content.push(ContentBlock::Image { .. }); // -> bail on antigravity

// after
let blocks: Vec<_> = message.content.into_iter().filter(|b| matches!(b, ContentBlock::Text { .. })).collect();
Defensive patterns

Strategy: validation

Validate before calling

for msg in &request.messages {
    for block in &msg.content {
        anyhow::ensure!(
            matches!(block, ContentBlock::Text { .. }),
            "cloud-code accepts text parts only; found non-text block"
        );
    }
}

Type guard

fn content_is_text_only(messages: &[ChatMessage]) -> bool {
    messages.iter().all(|m| m.content.iter().all(|b| matches!(b, ContentBlock::Text { .. })))
}

Try / catch

match client.create_message_stream(request).await {
    Ok(s) => Ok(s),
    Err(err) if err.to_string().contains("text parts only") => {
        let text_only = strip_non_text_blocks(request); // degrade gracefully
        client.create_message_stream(text_only).await
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: Any message in the request containing a content block that is not `ContentBlock::Text` — attaching a screenshot, replaying a tool_use call, or including a tool_result block.

Common situations: Multimodal turns (images) sent to antigravity; replaying an assistant turn that contains tool calls from an earlier provider; tool outputs appended as structured blocks.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/2269cab6a60cbd59. Report an issue: GitHub.