fix: handle non-image media types in Claude relay to prevent nil pointer panic#3531
fix: handle non-image media types in Claude relay to prevent nil pointer panic#3531Panniantong wants to merge 1 commit intoQuantumNous:mainfrom
Conversation
Handle ContentTypeFile (PDF/document) separately from image content in RequestOpenAI2ClaudeMessage. Previously, all non-text content was treated as image, causing nil pointer dereference when GetImageMedia() returned nil for file/document types. - Add ContentTypeFile branch before the generic image handler - Convert PDF/text files to Claude document blocks - Add nil guard for GetImageMedia() as safety fallback Fixes QuantumNous#3481
WalkthroughThe change extends media-content parsing in Claude relay to handle file uploads by extracting file payloads, converting them to base64, and classifying them as documents or images based on MIME type. It adds defensive nil checks to prevent nil pointer dereference panics when processing non-image media content. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@relay/channel/claude/relay-claude.go`:
- Around line 361-371: The code currently always treats file.FileData as base64
(using types.NewBase64FileSource) and classifies anything not PDF/text as
"image", which breaks for URL-backed file_data and non-image MIME types; update
the logic in the block that builds fileSource and sets claudeMediaMessage.Type
to first detect if file.FileData is a URL (e.g.,
strings.HasPrefix(file.FileData, "http://") or "https://") and create a URL file
source (use the library's URL file source constructor instead of
types.NewBase64FileSource) so service.GetBase64Data can fetch/convert it, then
inspect the returned mimeType and gate on it strictly: set
claudeMediaMessage.Type = "image" only when strings.HasPrefix(mimeType,
"image/"), set "document" for "application/pdf" or strings.HasPrefix(mimeType,
"text/"), and otherwise return an error or skip building the media block to
avoid sending invalid upstream requests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ef76cee3-dceb-44c9-9b55-9c3145af90db
📒 Files selected for processing (1)
relay/channel/claude/relay-claude.go
| fileSource := types.NewBase64FileSource(file.FileData, "") | ||
| base64Data, mimeType, err := service.GetBase64Data(c, fileSource, "formatting file for Claude") | ||
| if err != nil { | ||
| return nil, fmt.Errorf("get file data failed: %s", err.Error()) | ||
| } | ||
| // PDF and text documents use "document" type, others use "image" | ||
| if strings.HasPrefix(mimeType, "application/pdf") || strings.HasPrefix(mimeType, "text/") { | ||
| claudeMediaMessage.Type = "document" | ||
| } else { | ||
| claudeMediaMessage.Type = "image" | ||
| } |
There was a problem hiding this comment.
Handle URL-backed file_data and MIME gating before building Claude media blocks.
At Line 361, file.FileData is always treated as base64. If the client sends a URL payload, conversion fails. Also, at Lines 367-371, any non-PDF/non-text file is labeled as "image" even when MIME is not image/*, which can produce invalid upstream requests.
💡 Suggested fix
- fileSource := types.NewBase64FileSource(file.FileData, "")
+ if strings.TrimSpace(file.FileData) == "" {
+ continue
+ }
+ var fileSource *types.FileSource
+ if strings.HasPrefix(file.FileData, "http://") || strings.HasPrefix(file.FileData, "https://") {
+ fileSource = types.NewURLFileSource(file.FileData)
+ } else {
+ fileSource = types.NewBase64FileSource(file.FileData, "")
+ }
base64Data, mimeType, err := service.GetBase64Data(c, fileSource, "formatting file for Claude")
if err != nil {
return nil, fmt.Errorf("get file data failed: %s", err.Error())
}
- // PDF and text documents use "document" type, others use "image"
+ // PDF/text -> document; image/* -> image; others unsupported
if strings.HasPrefix(mimeType, "application/pdf") || strings.HasPrefix(mimeType, "text/") {
claudeMediaMessage.Type = "document"
- } else {
+ } else if strings.HasPrefix(mimeType, "image/") {
claudeMediaMessage.Type = "image"
+ } else {
+ continue
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@relay/channel/claude/relay-claude.go` around lines 361 - 371, The code
currently always treats file.FileData as base64 (using
types.NewBase64FileSource) and classifies anything not PDF/text as "image",
which breaks for URL-backed file_data and non-image MIME types; update the logic
in the block that builds fileSource and sets claudeMediaMessage.Type to first
detect if file.FileData is a URL (e.g., strings.HasPrefix(file.FileData,
"http://") or "https://") and create a URL file source (use the library's URL
file source constructor instead of types.NewBase64FileSource) so
service.GetBase64Data can fetch/convert it, then inspect the returned mimeType
and gate on it strictly: set claudeMediaMessage.Type = "image" only when
strings.HasPrefix(mimeType, "image/"), set "document" for "application/pdf" or
strings.HasPrefix(mimeType, "text/"), and otherwise return an error or skip
building the media block to avoid sending invalid upstream requests.
Summary
ContentTypeFilehandling inRequestOpenAI2ClaudeMessagebefore the generic image branchdocumentblocks instead of treating them as imagesGetImageMedia()as safety fallback for other unknown content typesProblem
When users upload PDF files via OpenAI-compatible clients (e.g., CherryStudio), the request contains
type: "file"content blocks. The current code treats all non-text content as images and callsGetImageMedia(), which returnsnilfor file types. AccessingimageUrl.Urlon the nil pointer causes a panic crash.Root Cause
relay-claude.go:~352— theelsebranch aftertype == "text"assumes everything else is an image, butContentTypeFile(PDF/documents) has noImageUrlfield, soGetImageMedia()returnsnil.Fix
ContentTypeFilebranch: Intercepts file-type content before the image handler. UsesGetFile()to extract file data, then converts to Claude'sdocumentblock format (for PDF/text) orimageblock (for other file types).GetImageMedia(): Addedif imageUrl == nil { continue }in the existing image branch as a safety net for any other unhandled content types.Reference
relay/channel/gemini/relay-gemini.go🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes