zed-industries/zed · error

User content must contain at least one part

Error message

User content must contain at least one part

What it means

validate_generate_content_request locates the first content item with role == User and rejects the request if its 'parts' vector is empty. A user turn with zero parts serializes to an empty message that Google's API refuses, so the guard catches it client-side.

Source

Thrown at crates/google_ai/src/google_ai.rs:94

    }
}

pub fn validate_generate_content_request(request: &GenerateContentRequest) -> Result<()> {
    if request.model.is_empty() {
        bail!("Model must be specified");
    }

    if request.contents.is_empty() {
        bail!("Request must contain at least one content item");
    }

    if let Some(user_content) = request
        .contents
        .iter()
        .find(|content| content.role == Role::User)
        && user_content.parts.is_empty()
    {
        bail!("User content must contain at least one part");
    }

    Ok(())
}

#[derive(Debug, Serialize, Deserialize)]
pub enum Task {
    #[serde(rename = "generateContent")]
    GenerateContent,
    #[serde(rename = "streamGenerateContent")]
    StreamGenerateContent,
    #[serde(rename = "embedContent")]
    EmbedContent,
    #[serde(rename = "batchEmbedContents")]
    BatchEmbedContents,
}

#[derive(Debug, Serialize, Deserialize)]

View on GitHub (pinned to 5a9b9558db)

Solutions

  1. Ensure user content carries at least one part (usually a text part)
  2. When mapping history, drop the whole content item if all its parts were filtered out, or insert a placeholder text part
  3. Add unit tests over the message-mapping code for degenerate histories

Example fix

// before
Content { role: Role::User, parts: vec![] } // passes type checks, fails validation

// after: either fill a part or omit the empty content entirely
Content { role: Role::User, parts: vec![Part::TextPart(" ".into())] }
Defensive patterns

Strategy: validation

Validate before calling

// before calling the API
if let Some(user_content) = request.contents.iter().find(|c| c.role == Role::User) {
    anyhow::ensure!(!user_content.parts.is_empty(), "user content must have at least one part");
}

Type guard

fn user_content_is_nonempty(request: &GenerateContentRequest) -> bool {
    request.contents.iter().find(|c| c.role == Role::User)
        .map(|c| !c.parts.is_empty()).unwrap_or(true)
}

Prevention

When it happens

Trigger: A user message whose parts list is empty because mapping code filtered out every part (unsupported content types); manually constructed Content structs in tests or glue code; compaction or editing logic that removes parts but keeps the container.

Common situations: History conversion drops image/thinking/redacted parts and leaves nothing; message structs built with vec![] parts; an empty user prompt after trimming.

Related errors


AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20). Data as JSON: /api/errors/f7da52069471f408. Report an issue: GitHub.