You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
OpenAI Responses API is sent Chat Completions content parts (type: "text"): live vision examples 400, fall back, then fail with invalid_image_url #3934
Live runs of the in-tree vision examples (examples/python/agents/image-agent.py, image-to-text-agent.py) against gpt-4o-mini hit this provider error before Chat Completions fallback:
Responses API failed, falling back to Chat Completions: Error code: 400 - {
"error": {
"message": "Invalid value: 'text'. Supported values are: 'input_text', 'input_image', 'input_audio', 'output_text', 'refusal', 'input_file', 'computer_screenshot', 'summary_text', and 'encrypted_content'.",
"type": "invalid_request_error",
"param": "input[0].content[0].type",
"code": "invalid_value"
}
}
Then Chat Completions failed on the same turn:
Failed to download image from image.jpg. Image URL is invalid.
OpenAIClient._use_responses_api("gpt-4o-mini") is True (official OpenAI, no custom base_url, SDK has responses). _build_responses_input maps system messages and tool calls, then appends the remaining Chat Completions messages unchanged:
else:
input_items.append(msg)
Chat Completions multimodal parts use "type": "text" and "type": "image_url". The Responses API requires "input_text" and "input_image". The 400 is exactly that mismatch (param: input[0].content[0].type).
Fallback does not save the example: a local filename image.jpg is not an HTTP URL, so Chat Completions returns invalid_image_url. The process can still exit 0 while printing stacked Error panels — the corpus harness counted these as “pass.”
Validated on main @ 43bea02, live OpenAI, example wall times 37.3s and 40.2s of failed API round-trips.
Workaround today: disable Responses API (custom base_url, or a model _use_responses_api rejects) and pass a public https:// image URL. Neither is the documented vision example.
Problem Statement
Vision / multimodal agents must:
Send user text + image to the active OpenAI API surface
Use the part types that surface documents
Fail loudly (non-zero) when the image cannot be read
Not burn ~40s on a guaranteed-400 mapping bug
gpt-4o-mini on the official API goes through Responses first. The transform is lossy for any message whose content is a list of parts. Every vision agent, screenshot tool, and “analyze this file” flow on OpenAI models is on this path.
Live execution evidence
From image-agent.py (live, gpt-4o-mini):
WARNING Responses API failed, falling back to Chat Completions: Error code: 400 -
Invalid value: 'text'. Supported values are: 'input_text', 'input_image', ...
param: input[0].content[0].type
ERROR Error creating async completion: Error code: 400 -
Failed to download image from image.jpg. Image URL is invalid.
ERROR Unified chat completion failed: ... invalid_image_url
The same pair of errors repeated (two chat attempts). Wall clock 37.251s, process exit 0.
image-to-text-agent.py: same Responses 400, same image.jpg URL error, plus DuckDuckGo search is not available (missing extra). Wall 40.171s, exit 0.
This is not a missing-key problem. The key was valid; the payload schema was wrong, then the image locator was a local path.
Expected vs actual
Expected
Actual
Responses input[].content[].type is input_text / input_image
text (Chat Completions name) → 400
Local file becomes input_image with bytes or data URL
Passed through as image.jpg string → invalid_image_url
Example exits non-zero on provider 400
Exit 0, rich Error panels
Fallback is rare
Fallback is every multimodal Responses call with list content
Repro
# Minimal shape that _build_responses_input currently forwards:messages= [
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image"},
{"type": "image_url", "image_url": {"url": "image.jpg"}},
],
}
]
Run any Agent vision example that builds that shape against gpt-4o-mini with a real OPENAI_API_KEY.
python examples/python/agents/image-agent.py
Expected: one Responses (or Completions) call that accepts the image.
Actual: Responses 400 on type=text, fallback, Completions 400 on image.jpg.
Impact analysis
Developer impact
Vision examples on the default OpenAI model look “runnable” (exit 0) and are broken. Debugging requires noticing a warning (Responses API failed, falling back) rather than a hard error. Time-to-green for multimodal is ~40s of failed HTTP per example.
Business impact
OpenAI’s current default API for these models is Responses. Shipping a transform that 400s on the first content part means official-API vision is not production-ready. Customers on Azure/custom base_url may not see it (_use_responses_api returns False) — so CI that mocks or uses a proxy never catches it.
User impact
“Analyze this screenshot / PDF page / photo” agents fail with invalid_image_url or a cryptic Invalid value: 'text'. Users think their file is bad. It is the SDK mapping.
param: input[0].content[0].type in the live 400 is the first part of the first forwarded user message.
Second failure: even a perfect Responses mapper will 400/fail if the URL is a relative filesystem path. Examples pass image.jpg. Chat Completions tries to GET it as a URL. There is no Path.read_bytes() → data URL (or input_file) step on this path.
Sequence
sequenceDiagram
participant E as Vision example
participant A as Agent
participant C as OpenAIClient
participant R as Responses API
participant CC as Chat Completions
E->>A: image.jpg + prompt
A->>C: acreate_completion (gpt-4o-mini)
C->>C: _use_responses_api True
C->>R: input[0].content[0].type = "text"
R-->>C: 400 invalid_value
C->>C: warning, fall through
C->>CC: image_url url=image.jpg
CC-->>C: 400 invalid_image_url
C-->>A: exception in chat
A-->>E: Error panel, exit 0
Executive Summary
Live runs of the in-tree vision examples (
examples/python/agents/image-agent.py,image-to-text-agent.py) againstgpt-4o-minihit this provider error before Chat Completions fallback:Then Chat Completions failed on the same turn:
OpenAIClient._use_responses_api("gpt-4o-mini")is True (official OpenAI, no custombase_url, SDK hasresponses)._build_responses_inputmaps system messages and tool calls, then appends the remaining Chat Completions messages unchanged:Chat Completions multimodal parts use
"type": "text"and"type": "image_url". The Responses API requires"input_text"and"input_image". The 400 is exactly that mismatch (param: input[0].content[0].type).Fallback does not save the example: a local filename
image.jpgis not an HTTP URL, so Chat Completions returnsinvalid_image_url. The process can still exit 0 while printing stacked Error panels — the corpus harness counted these as “pass.”Validated on
main@43bea02, live OpenAI, example wall times 37.3s and 40.2s of failed API round-trips.Workaround today: disable Responses API (custom
base_url, or a model_use_responses_apirejects) and pass a publichttps://image URL. Neither is the documented vision example.Problem Statement
Vision / multimodal agents must:
gpt-4o-minion the official API goes through Responses first. The transform is lossy for any message whosecontentis a list of parts. Every vision agent, screenshot tool, and “analyze this file” flow on OpenAI models is on this path.Live execution evidence
From
image-agent.py(live,gpt-4o-mini):The same pair of errors repeated (two chat attempts). Wall clock 37.251s, process exit 0.
image-to-text-agent.py: same Responses 400, sameimage.jpgURL error, plusDuckDuckGo search is not available(missing extra). Wall 40.171s, exit 0.This is not a missing-key problem. The key was valid; the payload schema was wrong, then the image locator was a local path.
Expected vs actual
input[].content[].typeisinput_text/input_imagetext(Chat Completions name) → 400input_imagewith bytes or data URLimage.jpgstring →invalid_image_urlRepro
Run any Agent vision example that builds that shape against
gpt-4o-miniwith a realOPENAI_API_KEY.Expected: one Responses (or Completions) call that accepts the image.
Actual: Responses 400 on
type=text, fallback, Completions 400 onimage.jpg.Impact analysis
Developer impact
Vision examples on the default OpenAI model look “runnable” (exit 0) and are broken. Debugging requires noticing a warning (
Responses API failed, falling back) rather than a hard error. Time-to-green for multimodal is ~40s of failed HTTP per example.Business impact
OpenAI’s current default API for these models is Responses. Shipping a transform that 400s on the first content part means official-API vision is not production-ready. Customers on Azure/custom
base_urlmay not see it (_use_responses_apireturns False) — so CI that mocks or uses a proxy never catches it.User impact
“Analyze this screenshot / PDF page / photo” agents fail with
invalid_image_urlor a crypticInvalid value: 'text'. Users think their file is bad. It is the SDK mapping.Root cause hypothesis
User/assistant messages with
content: strhappen to work (Responses accepts string content in some cases). User messages with part lists do not:{"type": "text", "text": "..."}{"type": "input_text", "text": "..."}{"type": "image_url", "image_url": {"url": "https://..."}}{"type": "input_image", "image_url": "https://..."}(flat URL)param: input[0].content[0].typein the live 400 is the first part of the first forwarded user message.Second failure: even a perfect Responses mapper will 400/fail if the URL is a relative filesystem path. Examples pass
image.jpg. Chat Completions tries to GET it as a URL. There is noPath.read_bytes()→ data URL (orinput_file) step on this path.Sequence
sequenceDiagram participant E as Vision example participant A as Agent participant C as OpenAIClient participant R as Responses API participant CC as Chat Completions E->>A: image.jpg + prompt A->>C: acreate_completion (gpt-4o-mini) C->>C: _use_responses_api True C->>R: input[0].content[0].type = "text" R-->>C: 400 invalid_value C->>C: warning, fall through C->>CC: image_url url=image.jpg CC-->>C: 400 invalid_image_url C-->>A: exception in chat A-->>E: Error panel, exit 0Proposed fix (with code)
1. Map content parts in
_build_responses_inputFor the
else: input_items.append(msg)branch:Do not forward raw Chat Completions messages into
params["input"].2. Local files → data URLs (both APIs)
Use this in both Responses mapping and Chat Completions
image_urlconstruction so fallback does not 400 onimage.jpg.3. Examples: exit non-zero on chat failure
Vision examples should
sys.exit(1)when the agent returns an Error panel / exception. Exit 0 with printed errors hides this from CI.4. Tests
A test that only mocks
responses.createsuccess will not catch this; the live 400 is on request shape.Architecture
Today the MAP step is missing; local-path promotion is missing.
Performance evidence
image-agent.pyimage-to-text-agent.py~40s is failed round-trips, not inference. A correct mapper is one successful call.
Before vs after
Before: Default OpenAI vision → Responses 400 on
type=text→ fallback →invalid_image_urlon local files → exit 0.After: Parts mapped; local files inlined; examples fail CI if the provider 400s; unit tests lock the Responses schema.
Out of scope
opencv-python/ddgsextras (separate example deps)image: falsetoday)Related
code -pconstructor crash._use_responses_apiskipping whenbase_urlis set explains why some environments never see the 400.