Summary
When routing an OpenAI-format chat completion request containing a data: URI in an image_url.url content part to an anthropic_messages-format target, Switchyard forwards the string verbatim into Anthropic's image content block as a URL-type source (source: {type: "url", url: "data:image/png;base64,..."}). Anthropic's API correctly rejects this, since a URL-type source must be a real http(s):// link, not a base64 data URI. The resulting error is opaque to callers: it's returned as a generic upstream 400 with message "Only HTTPS URLs are supported.", giving no indication that the actual problem is the missing data-URI translation.
Expected behavior
Per OpenAI's chat completions API, image_url.url may be either a real http(s):// URL or a data:<mime>;base64,<data> URI (this is the standard way OpenAI-compatible clients send inline images without external hosting). When translating to Anthropic's Messages API format, Switchyard should detect the data: prefix, parse out the media type and base64 payload, and emit Anthropic's base64-type image source instead:
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "<payload>"}}
URLs that are already http(s):// should presumably continue to pass through as Anthropic's URL-type source unchanged.
Steps to reproduce
Configuration: a target with format = "anthropic_messages" pointing at the real Anthropic API (base_url = "https://api.anthropic.com").
Request (OpenAI-format, sent to Switchyard's /v1/chat/completions):
{
"model": "<anthropic-backed route>",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "What color is this?"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,<...>"}}
]
}]
}
Observed response: HTTP 400, {"error": {"code": "upstream_error", "message": "Only HTTPS URLs are supported.", "type": "upstream_error"}}.
Confirmation this is translation-side, not client/config error
- The same request against a
format = "openai_chat" target (Google's OpenAI-compatible Gemini endpoint, passthrough with no format translation) succeeds and correctly describes the image — so the base64 payload itself is well-formed and the issue is specific to the Anthropic translation path.
- The literal error string
"Only HTTPS URLs are supported." does not appear anywhere in the compiled Switchyard binary (checked via binary grep), confirming it's Anthropic's own API error being relayed through, not a Switchyard-side validation message — i.e. Switchyard is constructing a request Anthropic considers malformed, rather than rejecting it before the request is sent.
Environment
- Switchyard built from
main via cargo build --release (Docker image built same-day as this report).
- Reached via a target with
llm_client pointing at format = "anthropic_messages", base_url = "https://api.anthropic.com".
Summary
When routing an OpenAI-format chat completion request containing a
data:URI in animage_url.urlcontent part to ananthropic_messages-format target, Switchyard forwards the string verbatim into Anthropic'simagecontent block as a URL-type source (source: {type: "url", url: "data:image/png;base64,..."}). Anthropic's API correctly rejects this, since a URL-type source must be a realhttp(s)://link, not a base64 data URI. The resulting error is opaque to callers: it's returned as a generic upstream 400 with message"Only HTTPS URLs are supported.", giving no indication that the actual problem is the missing data-URI translation.Expected behavior
Per OpenAI's chat completions API,
image_url.urlmay be either a realhttp(s)://URL or adata:<mime>;base64,<data>URI (this is the standard way OpenAI-compatible clients send inline images without external hosting). When translating to Anthropic's Messages API format, Switchyard should detect thedata:prefix, parse out the media type and base64 payload, and emit Anthropic's base64-type image source instead:{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "<payload>"}}URLs that are already
http(s)://should presumably continue to pass through as Anthropic's URL-type source unchanged.Steps to reproduce
Configuration: a target with
format = "anthropic_messages"pointing at the real Anthropic API (base_url = "https://api.anthropic.com").Request (OpenAI-format, sent to Switchyard's
/v1/chat/completions):{ "model": "<anthropic-backed route>", "messages": [{ "role": "user", "content": [ {"type": "text", "text": "What color is this?"}, {"type": "image_url", "image_url": {"url": "data:image/png;base64,<...>"}} ] }] }Observed response: HTTP 400,
{"error": {"code": "upstream_error", "message": "Only HTTPS URLs are supported.", "type": "upstream_error"}}.Confirmation this is translation-side, not client/config error
format = "openai_chat"target (Google's OpenAI-compatible Gemini endpoint, passthrough with no format translation) succeeds and correctly describes the image — so the base64 payload itself is well-formed and the issue is specific to the Anthropic translation path."Only HTTPS URLs are supported."does not appear anywhere in the compiled Switchyard binary (checked via binary grep), confirming it's Anthropic's own API error being relayed through, not a Switchyard-side validation message — i.e. Switchyard is constructing a request Anthropic considers malformed, rather than rejecting it before the request is sent.Environment
mainviacargo build --release(Docker image built same-day as this report).llm_clientpointing atformat = "anthropic_messages",base_url = "https://api.anthropic.com".