fix: surface upstream errors on arena models instead of crashing (#29662)

Sending a message to an arena model failed with "'JSONResponse' object has no attribute 'body_iterator'" whenever the backing provider answered with an HTTP error, so the real error never reached the user. Non-streaming requests on an arena model, such as title and tag generation, broke the same way with "'JSONResponse' object is not a mapping".

The arena wrapper assumed the sub-model call always returns a stream for a streaming request and a dict for everything else, but the OpenAI-compatible router returns a plain response object as soon as the provider answers 4xx or 5xx. Both arms now hand that response straight back, which is exactly what the non-arena path already does, so the existing error handling turns it into the usual error message in the chat.

Verified against a matrix of streaming and non-streaming requests with the sub-model returning a stream, a dict, a JSONResponse and a PlainTextResponse: both crashes are gone and the two success paths are unchanged, including the selected_model_id prelude on the stream.

Fixes #29658
This commit is contained in:
Classic298 2026-09-04 23:17:02 +02:00 committed by GitHub
parent 4f419627f8
commit d75a7aaf54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -269,24 +269,25 @@ async def generate_chat_completion(
bypass_filter=True,
bypass_system_prompt=bypass_system_prompt,
)
# Upstream errors come back as a response object.
if not isinstance(response, StreamingResponse):
return response
return StreamingResponse(
stream_wrapper(response.body_iterator),
media_type='text/event-stream',
background=response.background,
)
else:
return {
**(
await generate_chat_completion(
request,
form_data,
user,
bypass_filter=True,
bypass_system_prompt=bypass_system_prompt,
)
),
'selected_model_id': selected_model_id,
}
response = await generate_chat_completion(
request,
form_data,
user,
bypass_filter=True,
bypass_system_prompt=bypass_system_prompt,
)
if not isinstance(response, dict):
return response
return {**response, 'selected_model_id': selected_model_id}
if model.get('pipe'):
# Below does not require bypass_filter because this is the only route the uses this function and it is already bypassing the filter