{"record":{"id":"62e98ebe7bdffa15","repo":"wavetermdev/waveterm","slug":"file-type-requires-mimetype","errorCode":null,"errorMessage":"file type requires mimetype","messagePattern":"file type requires mimetype","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/uctypes/uctypes.go","lineNumber":415,"sourceCode":"func (p *AIMessagePart) Validate() error {\n\tif p.Type == AIMessagePartTypeText {\n\t\tif p.Text == \"\" {\n\t\t\treturn fmt.Errorf(\"text type requires non-empty text field\")\n\t\t}\n\t\t// Check that no file fields are set\n\t\tif p.FileName != \"\" || p.MimeType != \"\" || len(p.Data) > 0 || p.URL != \"\" {\n\t\t\treturn fmt.Errorf(\"text type cannot have file fields set\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tif p.Type == AIMessagePartTypeFile {\n\t\tif p.Text != \"\" {\n\t\t\treturn fmt.Errorf(\"file type cannot have text field set\")\n\t\t}\n\n\t\tif p.MimeType == \"\" {\n\t\t\treturn fmt.Errorf(\"file type requires mimetype\")\n\t\t}\n\n\t\t// Either data or url (not both) must be set\n\t\thasData := len(p.Data) > 0\n\t\thasURL := p.URL != \"\"\n\n\t\tif !hasData && !hasURL {\n\t\t\treturn fmt.Errorf(\"file type requires either data or url\")\n\t\t}\n\n\t\tif hasData && hasURL {\n\t\t\treturn fmt.Errorf(\"file type cannot have both data and url set\")\n\t\t}\n\n\t\t// If URL is set, validate it's https or data URL\n\t\tif hasURL {\n\t\t\tparsedURL, err := url.Parse(p.URL)\n\t\t\tif err != nil {","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/uctypes/uctypes.go#L397-L433","documentation":"Validation error: a file-type message part is missing the required mimetype field.","triggerScenarios":"AIMessagePart{Type:\"file\", Data: data} or {Type:\"file\", URL: ...} with MimeType left empty, then Validate() is called (directly or via AIMessage.Validate on a POSTed message).","commonSituations":"Constructing a file part from raw bytes without sniffing the content type; JSON payloads omitting the \"mimetype\" key; inferring MIME from extension and getting empty string for extensionless files.","solutions":["Set MimeType explicitly, e.g. \"image/png\" or \"application/pdf\"","Detect the type with http.DetectContentType(data) before building the part","Fix the client JSON to include the \"mimetype\" field"],"exampleFix":"// before\npart := uctypes.AIMessagePart{Type: \"file\", Data: data}\n// after\npart := uctypes.AIMessagePart{Type: \"file\", MimeType: http.DetectContentType(data), Data: data}","handlingStrategy":"validation","validationCode":"func hasMimeType(p uctypes.AIMessagePart) bool {\n\treturn p.Type == uctypes.AIMessagePartTypeFile && p.MimeType != \"\"\n}\n// mime := http.DetectContentType(data) when unknown","typeGuard":"func asTypedFilePart(p uctypes.AIMessagePart) (mime string, ok bool) {\n\tif p.Type == uctypes.AIMessagePartTypeFile && p.MimeType != \"\" {\n\t\treturn p.MimeType, true\n\t}\n\treturn \"\", false\n}","tryCatchPattern":null,"preventionTips":["Sniff MIME with http.DetectContentType when the type is unknown","Include the \"mimetype\" key in client JSON payloads","Never build a file part literal without MimeType"],"tags":["validation","ai-messages","file-upload"],"backgroundTag":"schema-validation-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}