wavetermdev/waveterm · error
parts must not be empty
Error message
parts must not be empty
What it means
AIMessage.Validate requires at least one part; a message with an empty Parts slice is structurally meaningless in the UI message protocol and is rejected. This guarantees downstream consumers never iterate zero parts when rendering or processing the conversation.
Source
Thrown at pkg/aiusechat/uctypes/uctypes.go:385
type AIToolResult struct {
ToolName string `json:"toolname"`
ToolUseID string `json:"tooluseid"`
ErrorText string `json:"errortext,omitempty"`
Text string `json:"text,omitempty"`
}
func (m *AIMessage) GetMessageId() string {
return m.MessageId
}
func (m *AIMessage) Validate() error {
if m.MessageId == "" {
return fmt.Errorf("messageid must be set")
}
if len(m.Parts) == 0 {
return fmt.Errorf("parts must not be empty")
}
for i, part := range m.Parts {
if err := part.Validate(); err != nil {
return fmt.Errorf("part %d: %w", i, err)
}
}
return nil
}
func (p *AIMessagePart) Validate() error {
if p.Type == AIMessagePartTypeText {
if p.Text == "" {
return fmt.Errorf("text type requires non-empty text field")
}
// Check that no file fields are set
if p.FileName != "" || p.MimeType != "" || len(p.Data) > 0 || p.URL != "" {View on GitHub (pinned to a4447c1563)
Solutions
- Append at least one valid part (text/tool-use/etc.) before validating
- If the message is a streaming placeholder, defer Validate() until parts are populated
- Check upstream filtering that may be stripping all parts
- Fix the serializer so parts are not lost (e.g. omit-empty on the wrong field)
Example fix
// before
msg := &uctypes.AIMessage{MessageId: id} // no parts
err := msg.Validate() // "parts must not be empty"
// after
msg := &uctypes.AIMessage{MessageId: id, Parts: []uctypes.MessagePart{uctypes.NewTextPart("hello")}}
err := msg.Validate() Defensive patterns
Strategy: validation
Validate before calling
if len(msg.Parts) == 0 {
return fmt.Errorf("AIMessage %s requires at least one part", msg.MessageId)
} Type guard
func hasParts(m *uctypes.AIMessage) bool {
return m != nil && len(m.Parts) > 0
} Try / catch
if err := msg.Validate(); err != nil {
if strings.Contains(err.Error(), "parts must not be empty") {
// defer validation until parts are streamed in, or append a placeholder part
}
return err
} Prevention
- Do not validate streaming placeholder messages before parts arrive
- Ensure filtering logic never removes all parts
- Verify serializers round-trip the parts array
- Append content before constructing the AIMessage
When it happens
Trigger: Validate() on an AIMessage with MessageId set but len(Parts) == 0 — e.g. deserializing {"messageid":"x","parts":[]}, dropping all parts during transformation/filtering, or building a message before appending content.
Common situations: Streaming code that creates the message shell before parts arrive and validates too early; filtering logic that removes all invalid parts; serializers that omit empty slices and round-trip to empty.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- messageid must be set
- part %d: %w
- Image too large (>5MB)
- Unsupported or invalid image type: ${blob.type}
- Invalid CSS color: ${String(color)}
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/cf937759f02d4cfa.
Report an issue: GitHub.