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
- Ensure user content carries at least one part (usually a text part)
- When mapping history, drop the whole content item if all its parts were filtered out, or insert a placeholder text part
- 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 mapping history, drop content items whose parts were all filtered out instead of emitting empty ones
- Add round-trip tests: build request, validate, assert Ok
- Never construct Content structs with vec![] parts in glue code
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
- Google AI does not support custom tool calls
- Model must be specified
- Request must contain at least one content item
- Failed to connect to Ollama API: {} {}
AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20).
Data as JSON: /api/errors/f7da52069471f408.
Report an issue: GitHub.