{"record":{"id":"2ca7007c76182212","repo":"wavetermdev/waveterm","slug":"type-must-be-q-or-q-got-q","errorCode":null,"errorMessage":"type must be %q or %q, got %q","messagePattern":"type must be %q or %q, got %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/uctypes/uctypes.go","lineNumber":444,"sourceCode":"\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\n\t}\n\n\treturn fmt.Errorf(\"type must be %q or %q, got %q\", AIMessagePartTypeText, AIMessagePartTypeFile, p.Type)\n}\n\n// ---------------------\n// AI SDK Streaming Protocol\n\n// Type can be one of these consts...\n// text-start, text-delta, text-end,\n// reasoning-start, reasoning-delta, reasoning-end,\n// source-url, source-document,\n// file,\n// data-*,\n// tool-input-start, tool-input-delta, tool-input-available, tool-output-available,\n// error, start-step, finish-step, finish\ntype UseChatStreamPart struct {\n\tType string `json:\"type\"`\n\n\t// Text\n\tText string `json:\"text,omitempty\"`","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/uctypes/uctypes.go#L426-L462","documentation":"AIMessagePart.Validate() only accepts Type \"text\" or \"file\" (AIMessagePartTypeText/AIMessagePartTypeFile); any other Type string falls through both branches and fails with this message showing the valid values and the received one.","triggerScenarios":"AIMessagePart{Type:\"image\"} or {Type:\"\"} (empty type) passed to Validate(); client JSON using a different part vocabulary (e.g. \"image_url\", \"image/png\") than the two supported types.","commonSituations":"Porting from other AI SDK part formats (OpenAI content parts, AI SDK UI messages) without translating the type; typo like \"txt\" or \"files\"; forgetting to set Type at all on a manually built part.","solutions":["Set Type to \"text\" (AIMessagePartTypeText) for text content","Set Type to \"file\" (AIMessagePartTypeFile) for attachments","Translate foreign part types (e.g. \"image_url\" -> \"file\" with MimeType) before validating"],"exampleFix":"// before\npart := uctypes.AIMessagePart{Type: \"image\", URL: \"https://example.com/a.png\", MimeType: \"image/png\"}\n// after\npart := uctypes.AIMessagePart{Type: uctypes.AIMessagePartTypeFile, URL: \"https://example.com/a.png\", MimeType: \"image/png\"}","handlingStrategy":"type-guard","validationCode":"func knownPartType(t string) bool {\n\treturn t == uctypes.AIMessagePartTypeText || t == uctypes.AIMessagePartTypeFile\n}","typeGuard":"func classifyPart(p uctypes.AIMessagePart) (string, bool) {\n\tswitch p.Type {\n\tcase uctypes.AIMessagePartTypeText, uctypes.AIMessagePartTypeFile:\n\t\treturn p.Type, true\n\tdefault:\n\t\treturn \"\", false\n\t}\n}","tryCatchPattern":null,"preventionTips":["Use the AIMessagePartTypeText/AIMessagePartTypeFile constants, never raw strings","Translate third-party part types before constructing AIMessagePart","Always set Type explicitly on hand-built parts"],"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"}