{"record":{"id":"efeb8a62ccfba654","repo":"wavetermdev/waveterm","slug":"file-part-missing-mimetype-efeb8a","errorCode":null,"errorMessage":"file part missing mimetype","messagePattern":"file part missing mimetype","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/openai/openai-convertmessage.go","lineNumber":329,"sourceCode":"\t\t}\n\t\tif chatOpts.ChatId != \"\" {\n\t\t\treq.Header.Set(\"X-Wave-ChatId\", chatOpts.ChatId)\n\t\t}\n\t\treq.Header.Set(\"X-Wave-Version\", wavebase.WaveVersion)\n\t\treq.Header.Set(\"X-Wave-APIType\", uctypes.APIType_OpenAIResponses)\n\t\treq.Header.Set(\"X-Wave-RequestType\", chatOpts.GetWaveRequestType())\n\t}\n\n\treturn req, nil\n}\n\n// convertFileAIMessagePart converts a file AIMessagePart to OpenAI format\nfunc convertFileAIMessagePart(part uctypes.AIMessagePart) (*OpenAIMessageContent, error) {\n\tif part.Type != uctypes.AIMessagePartTypeFile {\n\t\treturn nil, fmt.Errorf(\"convertFileAIMessagePart expects 'file' type, got '%s'\", part.Type)\n\t}\n\tif part.MimeType == \"\" {\n\t\treturn nil, fmt.Errorf(\"file part missing mimetype\")\n\t}\n\n\t// Handle different file types\n\tswitch {\n\tcase strings.HasPrefix(part.MimeType, \"image/\"):\n\t\timageUrl, err := aiutil.ExtractImageUrl(part.Data, part.URL, part.MimeType)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &OpenAIMessageContent{\n\t\t\tType:       \"input_image\",\n\t\t\tImageUrl:   imageUrl,\n\t\t\tFilename:   part.FileName,\n\t\t\tPreviewUrl: part.PreviewUrl,\n\t\t}, nil\n\n\tcase part.MimeType == \"application/pdf\":","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/openai/openai-convertmessage.go#L311-L347","documentation":"A file-type message part reached convertFileAIMessagePart without a MimeType. The converter needs the mimetype to route the part to image, PDF, text, or directory handling, so a missing one is rejected outright. This is an input validation error, not a network error.","triggerScenarios":"Adding an AIMessagePart with Type 'file' but leaving MimeType empty (e.g. attached a file from disk without detecting its content type); APIs/paths that build parts from user upload metadata lacking a content-type header.","commonSituations":"Attachments uploaded through custom frontends that don't set MIME types; files with unrecognized extensions where mime detection returned empty; copying part-construction code and omitting MimeType.","solutions":["Set part.MimeType explicitly (e.g. \"image/png\", \"application/pdf\", \"text/plain\") before sending the message","Use http.DetectContentType on the file bytes to infer the mimetype when unknown","Validate message parts (type + mimetype + data/url present) before calling the chat API"],"exampleFix":"// before\npart := uctypes.AIMessagePart{Type: uctypes.AIMessagePartTypeFile, FileName: \"report.pdf\"}\n// after\npart := uctypes.AIMessagePart{Type: uctypes.AIMessagePartTypeFile, FileName: \"report.pdf\", MimeType: \"application/pdf\", Data: pdfBytes}","handlingStrategy":"validation","validationCode":"if part.Type == uctypes.AIMessagePartTypeFile && part.MimeType == \"\" {\n    part.MimeType = http.DetectContentType(part.Data) // infer from bytes\n}\nif part.MimeType == \"\" { return errors.New(\"file part missing mimetype\") }","typeGuard":"func hasMimetype(p uctypes.AIMessagePart) bool {\n    return p.Type == uctypes.AIMessagePartTypeFile && p.MimeType != \"\"\n}","tryCatchPattern":null,"preventionTips":["Set MimeType at part construction from upload metadata","Use http.DetectContentType as fallback for unknown files","Validate all parts in one pre-send pass"],"tags":["openai","message-conversion","mimetype","validation"],"backgroundTag":"missing-mimetype","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}