{"record":{"id":"c1cef3da201e4528","repo":"wavetermdev/waveterm","slug":"file-type-requires-either-data-or-url","errorCode":null,"errorMessage":"file type requires either data or url","messagePattern":"file type requires either data or url","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/uctypes/uctypes.go","lineNumber":423,"sourceCode":"\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 {\n\t\t\t\treturn fmt.Errorf(\"invalid url: %w\", err)\n\t\t\t}\n\n\t\t\tif parsedURL.Scheme != \"https\" && parsedURL.Scheme != \"data\" {\n\t\t\t\treturn fmt.Errorf(\"url must be https or data URL, got %q\", parsedURL.Scheme)\n\t\t\t}\n\t\t}\n\t\treturn nil","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/uctypes/uctypes.go#L405-L441","documentation":"Validation error: a file-type message part has neither inline data nor a URL; exactly one is required.","triggerScenarios":"AIMessagePart{Type:\"file\", MimeType:\"image/png\"} with empty Data and empty URL passed to Validate(). Happens when the upload step failed or the URL assignment was skipped.","commonSituations":"Asynchronous upload pipeline where the fetch/populate step was skipped; JSON where \"data\" is base64 empty string and no \"url\"; conditional code paths that set Data XOR URL but neither branch ran.","solutions":["Attach the content: set Data to the file bytes (base64 on the wire)","Or set URL to an https:// or data: URL for the file","Fix the upload/read step so Data or URL is actually populated before validation"],"exampleFix":"// before\npart := uctypes.AIMessagePart{Type: \"file\", MimeType: \"image/png\", FileName: \"a.png\"}\n// after\ndata, err := os.ReadFile(\"a.png\")\npart := uctypes.AIMessagePart{Type: \"file\", MimeType: \"image/png\", FileName: \"a.png\", Data: data}","handlingStrategy":"validation","validationCode":"func hasAttachmentContent(p uctypes.AIMessagePart) bool {\n\treturn p.Type == uctypes.AIMessagePartTypeFile && (len(p.Data) > 0 || p.URL != \"\")\n}","typeGuard":"func hasPayload(p uctypes.AIMessagePart) bool {\n\tif p.Type == uctypes.AIMessagePartTypeFile {\n\t\treturn len(p.Data) > 0 || p.URL != \"\"\n\t}\n\treturn false\n}","tryCatchPattern":null,"preventionTips":["Confirm the upload/read step succeeded before building the part","Fail fast in helpers when neither Data nor URL is available","Check base64 payloads decode to non-empty bytes before setting Data"],"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"}