wavetermdev/waveterm · error

part %d: %w

Error message

part %d: %w

What it means

After checking MessageId and non-empty Parts, AIMessage.Validate delegates to each part's own Validate() and wraps any failure as "part %d: %w" with the part's index. This tells you exactly which element in the Parts slice is invalid while preserving the underlying reason (invalid part type, empty content, etc.).

Source

Thrown at pkg/aiusechat/uctypes/uctypes.go:390

	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 != "" {
			return fmt.Errorf("text type cannot have file fields set")
		}
		return nil
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the wrapped inner error to see which part field failed, and fix that part at the reported index
  2. Validate each part individually (part.Validate()) to isolate the failure before assembling the message
  3. Regenerate or re-fetch the message if it came from an external/corrupted source
  4. Update part construction helpers so required sub-fields are always populated

Example fix

// before
parts := []uctypes.MessagePart{toolUsePart /* missing tool name */}
msg.Validate() // "part 0: ..."
// after
for i, p := range parts { if err := p.Validate(); err != nil { log.Printf("fix part %d: %v", i, err) } }
toolUsePart.ToolName = "delete_text_file"
msg.Validate() // nil
Defensive patterns

Strategy: validation

Validate before calling

for i, part := range msg.Parts {
    if err := part.Validate(); err != nil {
        return fmt.Errorf("part %d invalid before send: %w", i, err)
    }
}

Type guard

func allPartsValid(m *uctypes.AIMessage) bool {
    if m == nil { return false }
    for _, p := range m.Parts {
        if p.Validate() != nil { return false }
    }
    return true
}

Try / catch

if err := msg.Validate(); err != nil {
    var idx int
    if n, _ := fmt.Sscanf(err.Error(), "part %d:", &idx); n == 1 {
        log.Printf("invalid part at index %d: %v", idx, err)
    }
    return err
}

Prevention

When it happens

Trigger: Validate() on an AIMessage whose i-th part fails its own validation — e.g. a tool-use part missing required fields, an empty text part, or a nil/unsupported part at that index.

Common situations: Corrupted or partially-deserialized messages from external sources; hand-built parts missing required sub-fields; protocol changes where older part shapes no longer validate.

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/ac09ff79b60ec020. Report an issue: GitHub.