{"record":{"id":"a856087ef9f49508","repo":"wavetermdev/waveterm","slug":"invalid-aimessage-w","errorCode":null,"errorMessage":"invalid AIMessage: %w","messagePattern":"invalid AIMessage: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/anthropic/anthropic-convertmessage.go","lineNumber":463,"sourceCode":"\t\t\t\t},\n\t\t\t}, nil\n\t\t} else {\n\t\t\t// HTTP/HTTPS URL → not supported inline, would need to fetch\n\t\t\treturn nil, fmt.Errorf(\"dropping text/plain file with URL (must be fetched and converted to base64 or uploaded to Files API)\")\n\t\t}\n\n\tdefault:\n\t\t// Other media types → not supported inline, must upload and use file_id\n\t\treturn nil, fmt.Errorf(\"dropping file with unsupported media type '%s' (must be uploaded to Files API and sent as file_id)\", p.MediaType)\n\t}\n\n}\n\n// convertAIMessageToAnthropicChatMessage converts an AIMessage to anthropicChatMessage\n// These messages are ALWAYS role \"user\"\nfunc ConvertAIMessageToAnthropicChatMessage(aiMsg uctypes.AIMessage) (*anthropicChatMessage, error) {\n\tif err := aiMsg.Validate(); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid AIMessage: %w\", err)\n\t}\n\n\tvar contentBlocks []anthropicMessageContentBlock\n\n\tfor i, part := range aiMsg.Parts {\n\t\tswitch part.Type {\n\t\tcase uctypes.AIMessagePartTypeText:\n\t\t\tif part.Text == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"part %d: text type requires non-empty text field\", i)\n\t\t\t}\n\t\t\tcontentBlocks = append(contentBlocks, anthropicMessageContentBlock{\n\t\t\t\tType: \"text\",\n\t\t\t\tText: part.Text,\n\t\t\t})\n\n\t\tcase uctypes.AIMessagePartTypeFile:\n\t\t\tblock, err := convertFileAIMessagePart(part)\n\t\t\tif err != nil {","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/anthropic/anthropic-convertmessage.go#L445-L481","documentation":"ConvertAIMessageToAnthropicChatMessage first runs aiMsg.Validate() and wraps any validation failure as \"invalid AIMessage\". This means the AIMessage struct itself failed the library's own validation rules (e.g. missing required fields like MessageId, no parts, or invalid part structure), before any per-part conversion happens.","triggerScenarios":"Calling ConvertAIMessageToAnthropicChatMessage (directly or via ConvertAIMessageToNativeChatMessage) with an AIMessage that has an empty Parts slice, an unset/invalid required field, or otherwise fails uctypes.AIMessage.Validate().","commonSituations":"Constructing AIMessage programmatically while skipping required fields; deserializing model output from JSON where MessageId/Parts were absent; passing a zero-value AIMessage{}; version drift where Validate() gained new required-field rules.","solutions":["Call aiMsg.Validate() yourself before conversion and log the wrapped error to see the exact rule that failed","Populate required fields (MessageId, at least one valid Part)","Check that JSON unmarshaling into uctypes.AIMessage maps the expected fields (correct json tags)","Re-run validation after upgrading the library in case Validate() requirements changed"],"exampleFix":"// before\nmsg := uctypes.AIMessage{Parts: []uctypes.AIMessagePart{{Type: uctypes.AIMessagePartTypeText, Text: \"hi\"}}}\nout, err := ConvertAIMessageToAnthropicChatMessage(msg) // fails validation\n// after\nmsg := uctypes.AIMessage{MessageId: \"msg_123\", Parts: []uctypes.AIMessagePart{{Type: uctypes.AIMessagePartTypeText, Text: \"hi\"}}}\nif err := msg.Validate(); err != nil { log.Fatal(err) }\nout, err := ConvertAIMessageToAnthropicChatMessage(msg)","handlingStrategy":"validation","validationCode":"if err := aiMsg.Validate(); err != nil {\n    return fmt.Errorf(\"AIMessage not convertible: %w\", err)\n}\nout, err := ConvertAIMessageToAnthropicChatMessage(aiMsg)","typeGuard":"func isValidAIMessage(m uctypes.AIMessage) bool {\n    return m.Validate() == nil\n}","tryCatchPattern":"out, err := ConvertAIMessageToAnthropicChatMessage(aiMsg)\nif err != nil {\n    var verr *uctypes.ValidationError\n    if errors.As(err, &verr) {\n        log.Printf(\"invalid AIMessage (%s): %v\", aiMsg.MessageId, verr)\n        return fallbackPlainMessage(aiMsg)\n    }\n    return err\n}","preventionTips":["Call Validate() on messages right after construction/unmarshal, not just before sending","Ensure JSON unmarshaling maps MessageId and Parts via correct tags","Re-check validation rules after library upgrades","Never pass zero-value AIMessage structs to converters"],"tags":["go","validation","anthropic","message-conversion"],"backgroundTag":"message-validation-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}