{"record":{"id":"a7a9a59e4068ceb0","repo":"wavetermdev/waveterm","slug":"convertfileuimessagepart-expects-file-type-got","errorCode":null,"errorMessage":"convertFileUIMessagePart expects 'file' type, got '%s'","messagePattern":"convertFileUIMessagePart expects 'file' type, got '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/anthropic/anthropic-convertmessage.go","lineNumber":354,"sourceCode":"func convertPartsToAnthropicBlocks(parts []uctypes.UIMessagePart, role string) ([]anthropicMessageContentBlock, error) {\n\tvar blocks []anthropicMessageContentBlock\n\n\tfor _, p := range parts {\n\t\tpartBlocks, err := convertPartToAnthropicBlocks(p, role, len(blocks))\n\t\tif err != nil {\n\t\t\tlog.Printf(\"anthropic: %v\", err)\n\t\t\tcontinue\n\t\t}\n\t\tblocks = append(blocks, partBlocks...)\n\t}\n\n\treturn blocks, nil\n}\n\n// convertFileUIMessagePart converts a file part to Anthropic image or document block format\nfunc convertFileUIMessagePart(p uctypes.UIMessagePart) (*anthropicMessageContentBlock, error) {\n\tif p.Type != \"file\" {\n\t\treturn nil, fmt.Errorf(\"convertFileUIMessagePart expects 'file' type, got '%s'\", p.Type)\n\t}\n\tif p.URL == \"\" {\n\t\treturn nil, errors.New(\"file part missing url\")\n\t}\n\tif p.MediaType == \"\" {\n\t\treturn nil, errors.New(\"file part missing mediaType\")\n\t}\n\n\t// Validate URL protocol - only allow data:, http:, https:\n\tif !strings.HasPrefix(p.URL, \"data:\") &&\n\t\t!strings.HasPrefix(p.URL, \"http://\") &&\n\t\t!strings.HasPrefix(p.URL, \"https://\") {\n\t\treturn nil, fmt.Errorf(\"unsupported URL protocol in file part: %s\", p.URL)\n\t}\n\n\t// Branch on mediaType first to determine block type and constraints\n\tswitch {\n\tcase strings.HasPrefix(p.MediaType, \"image/\"):","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/anthropic/anthropic-convertmessage.go#L336-L372","documentation":"convertFileUIMessagePart is an internal dispatcher that only handles UIMessageParts whose Type is exactly \"file\". The library throws this error when a caller (via convertPartToAnthropicBlocks) routes a part of a different type into the file conversion path, indicating an internal mis-dispatch or a caller constructing parts with a wrong/empty Type field. It is a defensive type check, not a data-content validation.","triggerScenarios":"Passing a UIMessagePart with Type set to something other than \"file\" (e.g. \"text\", \"image\", \"\", or a custom type) such that convertPartToAnthropicBlocks dispatches it to convertFileUIMessagePart.","commonSituations":"Building message parts by hand without setting Type; deserializing UI messages from JSON where the type discriminator was lost or renamed; a mapping bug in the caller that sends non-file parts down the file branch.","solutions":["Set the part's Type field to \"file\" (uctypes.UIMessagePartTypeFile) before adding it to the message","Check that your code routes only file parts into the file conversion path (fix the dispatch in convertPartToAnthropicBlocks callers)","Log/inspect p.Type at the call site to find where the mis-typed part originates"],"exampleFix":"// before\npart := uctypes.UIMessagePart{URL: \"data:text/plain;base64,aGk=\", MediaType: \"text/plain\"}\n// after\npart := uctypes.UIMessagePart{Type: \"file\", URL: \"data:text/plain;base64,aGk=\", MediaType: \"text/plain\"}","handlingStrategy":"type-guard","validationCode":"func isFileUIPart(p uctypes.UIMessagePart) bool { return p.Type == \"file\" }\nif !isFileUIPart(p) { return fmt.Errorf(\"skipping non-file part %q\", p.Type) }","typeGuard":"func isFileUIPart(p uctypes.UIMessagePart) bool {\n    return p.Type == \"file\"\n}","tryCatchPattern":"block, err := convertFileUIMessagePart(p)\nif err != nil {\n    if strings.Contains(err.Error(), \"expects 'file' type\") {\n        log.Printf(\"mis-typed part %q skipped\", p.Type)\n        return nil, nil // skip\n    }\n    return nil, err\n}","preventionTips":["Always set Type using the library's exported constants, never string literals","Validate parts with the type's Validate() method before conversion","Unit-test converters with all part types to catch dispatch bugs"],"tags":["go","type-mismatch","message-conversion","anthropic"],"backgroundTag":"wrong-part-type","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}