{"record":{"id":"f6382193c715df41","repo":"wavetermdev/waveterm","slug":"file-type-cannot-have-text-field-set","errorCode":null,"errorMessage":"file type cannot have text field set","messagePattern":"file type cannot have text field set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/uctypes/uctypes.go","lineNumber":411,"sourceCode":"\n\treturn nil\n}\n\nfunc (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","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/uctypes/uctypes.go#L393-L429","documentation":"Validation error: a message part of file type must not carry a text field; text and file payloads are mutually exclusive.","triggerScenarios":"Building AIMessagePart{Type:\"file\", Text:\"caption\", MimeType:..., Data:...} and calling Validate(). Common when a single struct is used to hold both a caption and the attachment.","commonSituations":"Client UIs that allow a caption with an upload; migration code from formats where a message had text+file in one object (e.g. some chat APIs); copy-paste of a text part with Type changed to \"file\" but Text left set.","solutions":["Set Text to \"\" on the file part","Emit a separate {\"type\":\"text\"} part for the caption ahead of the file part"],"exampleFix":"// before\npart := uctypes.AIMessagePart{Type: \"file\", Text: \"my screenshot\", MimeType: \"image/png\", Data: data}\n// after\nparts := []uctypes.AIMessagePart{\n\t{Type: \"text\", Text: \"my screenshot\"},\n\t{Type: \"file\", MimeType: \"image/png\", Data: data},\n}","handlingStrategy":"validation","validationCode":"func validFilePartNoText(p uctypes.AIMessagePart) bool {\n\treturn p.Type == uctypes.AIMessagePartTypeFile && p.Text == \"\"\n}","typeGuard":"func asFilePart(p uctypes.AIMessagePart) (*uctypes.AIMessagePart, bool) {\n\tif p.Type == uctypes.AIMessagePartTypeFile && p.Text == \"\" {\n\t\treturn &p, true\n\t}\n\treturn nil, false\n}","tryCatchPattern":null,"preventionTips":["Keep captions in separate text parts","Zero out the Text field when repurposing a part struct","Run Validate() on every part before sending"],"tags":["validation","ai-messages"],"backgroundTag":"schema-validation-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}