{"record":{"id":"157c7ad558068675","repo":"wavetermdev/waveterm","slug":"failed-to-decode-data-url-for-text-plain-file-w","errorCode":null,"errorMessage":"failed to decode data URL for text/plain file: %w","messagePattern":"failed to decode data URL for text/plain file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/aiutil/aiutil.go","lineNumber":94,"sourceCode":"\t\treturn url, nil\n\t}\n\tif len(data) > 0 {\n\t\tbase64Data := base64.StdEncoding.EncodeToString(data)\n\t\treturn fmt.Sprintf(\"data:%s;base64,%s\", mimeType, base64Data), nil\n\t}\n\treturn \"\", fmt.Errorf(\"file part missing both url and data\")\n}\n\n// ExtractTextData extracts text data from either Data field or URL field (data: URLs only)\nfunc ExtractTextData(data []byte, url string) ([]byte, error) {\n\tif len(data) > 0 {\n\t\treturn data, nil\n\t}\n\tif url != \"\" {\n\t\tif strings.HasPrefix(url, \"data:\") {\n\t\t\t_, decodedData, err := utilfn.DecodeDataURL(url)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to decode data URL for text/plain file: %w\", err)\n\t\t\t}\n\t\t\treturn decodedData, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"dropping text/plain file with URL (must be fetched and converted to data)\")\n\t}\n\treturn nil, fmt.Errorf(\"text/plain file part missing data\")\n}\n\n// FormatAttachedTextFile formats a text file attachment with proper encoding and deterministic suffix\nfunc FormatAttachedTextFile(fileName string, textContent []byte) string {\n\tif fileName == \"\" {\n\t\tfileName = \"untitled.txt\"\n\t}\n\n\tencodedFileName := strings.ReplaceAll(fileName, `\"`, \"&quot;\")\n\tquotedFileName := strconv.Quote(encodedFileName)\n\n\ttextStr := string(textContent)","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/aiutil/aiutil.go#L76-L112","documentation":"ExtractTextData decodes text/plain attachments. When the text content is supplied as a data: URL, it uses utilfn.DecodeDataURL to recover the raw bytes; if that decoding fails the error is wrapped and returned. This indicates the data URL itself is malformed (bad base64, missing/invalid media type, corrupt percent-encoding).","triggerScenarios":"Passing a non-empty url with the \"data:\" prefix to ExtractTextData where DecodeDataURL fails — e.g. base64 payload contains invalid characters, the URL is truncated, or the mediatype portion is malformed.","commonSituations":"Hand-building data: URLs with manual base64 encoding (wrong encoding name, stray whitespace/newlines); truncation of long data URLs by logs or config; percent-encoded content mangled during copy/paste.","solutions":["Regenerate the data URL with a standard encoder, e.g. \"data:text/plain;base64,\" + base64.StdEncoding.EncodeToString(data).","Check the wrapped inner error (err.Unwrap/strings) to see the exact base64/URL parse failure and fix the payload accordingly.","Pass the raw bytes via the data argument instead of a data: URL — that path bypasses decoding entirely.","Verify the URL was not truncated or line-wrapped in transport (config files, logs, databases)."],"exampleFix":"// before\nurl := \"data:text/plain;base64,\" + base64.URLEncoding.EncodeToString(data) // wrong alphabet\nb, err := aiutil.ExtractTextData(nil, url) // failed to decode data URL\n// after\nb, err := aiutil.ExtractTextData(data, \"\") // pass bytes directly","handlingStrategy":"validation","validationCode":"func validDataURL(u string) bool {\n    if !strings.HasPrefix(u, \"data:\") { return false }\n    idx := strings.Index(u, \"base64,\")\n    if idx < 0 { return false }\n    _, err := base64.StdEncoding.DecodeString(u[idx+len(\"base64,\"):])\n    return err == nil\n}","typeGuard":"func isDecodableDataURL(u string) bool { return strings.HasPrefix(u, \"data:\") && utilfnDecodeOK(u) }","tryCatchPattern":"b, err := aiutil.ExtractTextData(data, url)\nif err != nil {\n    return fmt.Errorf(\"text attachment unusable: %w\", err) // inspect %w for base64 cause\n}","preventionTips":["Always build data URLs with base64.StdEncoding, never URLEncoding, for this API","Pass raw bytes (data param) whenever you have them — avoids decoding entirely","Don't let data URLs pass through log truncation or line wrapping before use"],"tags":["data-url","base64","text-attachment"],"backgroundTag":"malformed-data-url","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}