{"record":{"id":"307f2f15c49f2ce8","repo":"wavetermdev/waveterm","slug":"part-d-unsupported-part-type-s","errorCode":null,"errorMessage":"part %d: unsupported part type '%s'","messagePattern":"part (.+?): unsupported part type '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/anthropic/anthropic-convertmessage.go","lineNumber":487,"sourceCode":"\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 {\n\t\t\t\treturn nil, fmt.Errorf(\"part %d: %w\", i, err)\n\t\t\t}\n\t\t\tcontentBlocks = append(contentBlocks, *block)\n\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"part %d: unsupported part type '%s'\", i, part.Type)\n\t\t}\n\t}\n\n\treturn &anthropicChatMessage{\n\t\tMessageId: aiMsg.MessageId,\n\t\tRole:      \"user\",\n\t\tContent:   contentBlocks,\n\t}, nil\n}\n\n// hasInlineData checks if the part has data available for inline use (either Data field or data URL)\nfunc hasInlineData(part uctypes.AIMessagePart) bool {\n\thasData := len(part.Data) > 0\n\thasURL := part.URL != \"\" && strings.HasPrefix(part.URL, \"data:\")\n\treturn hasData || hasURL\n}\n\n// extractBase64Data extracts base64 data from either the Data field or a data URL","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/anthropic/anthropic-convertmessage.go#L469-L505","documentation":"ConvertAIMessageToAnthropicChatMessage only understands two part types: text and file. Any other AIMessagePartType (e.g. tool-call, thinking, image-as-its-own-type, or unknown/garbage type values) hits the default branch and is rejected with the offending type name and its index.","triggerScenarios":"Appending an AIMessagePart whose Type is not AIMessagePartTypeText or AIMessagePartTypeFile (including \"\" from a zero-value part or a mistyped constant) to aiMsg.Parts and converting for Anthropic.","commonSituations":"Reusing AIMessage parts populated for a different provider (OpenAI tool calls) without filtering; typo'd type constants; unmarshal producing empty Type; newer library versions adding part types this converter does not handle.","solutions":["Filter aiMsg.Parts to only text and file types before conversion","Convert unsupported parts (e.g. tool calls) into their text/file equivalents or drop them","Set part.Type explicitly; never rely on zero values","Check for library version mismatches if a previously-accepted type is now rejected"],"exampleFix":"// before\nmsg := uctypes.AIMessage{MessageId: id, Parts: allParts}\n// after\nvar kept []uctypes.AIMessagePart\nfor _, p := range allParts {\n    if p.Type == uctypes.AIMessagePartTypeText || p.Type == uctypes.AIMessagePartTypeFile {\n        kept = append(kept, p)\n    }\n}\nmsg := uctypes.AIMessage{MessageId: id, Parts: kept}","handlingStrategy":"type-guard","validationCode":"var convertible []uctypes.AIMessagePart\nfor _, p := range aiMsg.Parts {\n    if p.Type == uctypes.AIMessagePartTypeText || p.Type == uctypes.AIMessagePartTypeFile {\n        convertible = append(convertible, p)\n    }\n}\naiMsg.Parts = convertible","typeGuard":"func isAnthropicConvertiblePart(p uctypes.AIMessagePart) bool {\n    return p.Type == uctypes.AIMessagePartTypeText || p.Type == uctypes.AIMessagePartTypeFile\n}","tryCatchPattern":"if err := convert(aiMsg); err != nil {\n    if strings.Contains(err.Error(), \"unsupported part type\") {\n        aiMsg.Parts = filterConvertibleParts(aiMsg.Parts)\n        return convert(aiMsg)\n    }\n    return err\n}","preventionTips":["Filter Parts to text/file types before Anthropic conversion","Use exported type constants; guard against \"\" from zero-value parts","When new part types appear in the library, update filters before upgrading"],"tags":["go","unsupported-type","anthropic","message-conversion"],"backgroundTag":"wrong-part-type","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}