{"record":{"id":"b17d252a606c6966","repo":"wavetermdev/waveterm","slug":"dropping-pdf-with-url-must-be-fetched-and-convert-b17d25","errorCode":null,"errorMessage":"dropping PDF with URL (must be fetched and converted to base64 data)","messagePattern":"dropping PDF with URL \\(must be fetched and converted to base64 data\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/openai/openai-convertmessage.go","lineNumber":351,"sourceCode":"\tswitch {\n\tcase strings.HasPrefix(part.MimeType, \"image/\"):\n\t\timageUrl, err := aiutil.ExtractImageUrl(part.Data, part.URL, part.MimeType)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &OpenAIMessageContent{\n\t\t\tType:       \"input_image\",\n\t\t\tImageUrl:   imageUrl,\n\t\t\tFilename:   part.FileName,\n\t\t\tPreviewUrl: part.PreviewUrl,\n\t\t}, nil\n\n\tcase part.MimeType == \"application/pdf\":\n\t\t// Handle PDFs - OpenAI only supports base64 data for PDFs, not URLs\n\t\tif len(part.Data) == 0 {\n\t\t\tif part.URL != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"dropping PDF with URL (must be fetched and converted to base64 data)\")\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"PDF file part missing data\")\n\t\t}\n\n\t\t// Convert raw data to base64\n\t\tbase64Data := base64.StdEncoding.EncodeToString(part.Data)\n\n\t\treturn &OpenAIMessageContent{\n\t\t\tType:       \"input_file\",\n\t\t\tFilename:   part.FileName, // Optional filename\n\t\t\tFileData:   base64Data,\n\t\t\tPreviewUrl: part.PreviewUrl,\n\t\t}, nil\n\n\tcase part.MimeType == \"text/plain\":\n\t\ttextData, err := aiutil.ExtractTextData(part.Data, part.URL)\n\t\tif err != nil {\n\t\t\treturn nil, err","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/openai/openai-convertmessage.go#L333-L369","documentation":"OpenAI's API only accepts PDFs as base64-encoded data, never as URLs. The converter found a PDF part with a URL but no inline Data, and returns this error instead of silently sending an unsupported URL-based PDF.","triggerScenarios":"Building a file part with MimeType \"application/pdf\", part.URL set to a web/CDN link, and part.Data empty; passing through attachment metadata from another provider (e.g. Anthropic/Claude-style URL PDFs) directly to the OpenAI backend.","commonSituations":"Migrating chat pipelines from Claude (which accepts PDF URLs) to OpenAI; storing files behind signed URLs and referencing them by link; frontend sending upload URLs instead of downloaded bytes.","solutions":["Fetch the PDF yourself, put the raw bytes into part.Data, and clear part.URL","Base64-encode is handled by the converter — only raw bytes are needed in Data","Pre-download attachments in your ingestion pipeline before constructing message parts"],"exampleFix":"// before\npart := uctypes.AIMessagePart{Type: \"file\", MimeType: \"application/pdf\", URL: \"https://cdn.example.com/doc.pdf\"}\n// after\ndata, _ := http.Get(part.URL) // fetch first\nbody, _ := io.ReadAll(data.Body)\npart := uctypes.AIMessagePart{Type: \"file\", MimeType: \"application/pdf\", Data: body}","handlingStrategy":"validation","validationCode":"func validatePDFPart(p uctypes.AIMessagePart) error {\n    if p.MimeType != \"application/pdf\" { return nil }\n    if len(p.Data) == 0 && p.URL != \"\" {\n        return errors.New(\"PDF has URL only; fetch bytes into Data first\")\n    }\n    return nil\n}","typeGuard":"func hasInlinePDFData(p uctypes.AIMessagePart) bool {\n    return p.MimeType == \"application/pdf\" && len(p.Data) > 0\n}","tryCatchPattern":null,"preventionTips":["Always download PDFs to bytes before attaching; never pass URLs","Normalize parts from other providers (Claude-style URL PDFs) at ingestion","Pre-send validation pass over all file parts"],"tags":["openai","pdf","message-conversion"],"backgroundTag":"pdf-url-not-supported","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}