Repository navigation
Description
Summary
On the hive provider (thehive.ai, adapter openai-chat) requests to /v1/chat/completions intermittently fail with an upstream 400 that opencodex reports as terminal, so a combo has nothing to fail over to and the turn dies:
{"error":{"message":"Provider error 400: {\"status_code\":400,\"message\":\"Received bad JSON request\"}","type":"invalid_request_error","code":"invalid_request_error"}}In the trace I looked at, one conversation had 176 successful turns, then a burst of 400s (~7 in ~100s), then normal service resumed after auto-compaction. So it is not a hard outage: the gateway rejects a specific request shape, and the same route serves the next request fine.
Environment
- opencodex 2.75.0
- provider
hive: baseUrlhttps://api-cdn.thehive.ai/api/v3, adapteropenai-chat, authModekey - model
deepseek-ai/deepseek-v4.1-flash(alsozai-org/glm-5.3-flash) - reproduced both directly against
hive/deepseek-ai/deepseek-v4.1-flashand viacombo/hive-fb(single target, strategy failover)
Reproductions
POST http://127.0.0.1:10102/v1/chat/completions, model hive/deepseek-ai/deepseek-v4.1-flash:
| Request body | Result |
|---|---|
messages[0] = {"role":"developer","content":"be terse"} |
400 Provider error 400: Bad Request |
messages[0] = {"role":"developer","content":[{"type":"text","text":"be terse"}]} |
400 Provider error 400: Bad Request |
messages[0] = {"role":"system","content":"be terse"} |
200 |
messages[0] = {"role":"system","content":[{"type":"text","text":"be terse"}]} |
200 |
messages[0] = {"role":"system","content":[{"type":"input_text","text":"be terse"}]} |
400 Provider error 400: Bad Request |
content contains a lone/unpaired surrogate, e.g. "...AB\ud800CD..." (valid JSON per RFC 8259) |
400 Provider error 400: Invalid payload: Missing model name |
content contains a matched surrogate pair (\ud83d\ude00) |
200 |
| 2 MB body / ~700k-token prompt | 200 (size/length is not the trigger; 4 MB returns a different, honest Please reduce the length… error) |
Findings: the Hive gateway rejects (a) the developer role and (b) any content part that is not {"type":"text",...}. It also mis-parses lone surrogates.
Why this is worth fixing in opencodex
-
comboFailureDecisiontreats this as terminal. The upstream code isinvalid_request_error, which the classifier maps to"stop", so a combo cannot hop even though the next target could serve the request. These look like request-local target incompatibilities (bad/decorated body for this gateway), which the hop rules already handle for other shapes. -
The
hivedestination's quirks are not recorded. The translated chat route foldsdeveloper→systemonly for the unrecorded default, and the native passthrough forwards roles verbatim unlessfoldDeveloperRoleToSystemis set for that destination. RecordingfoldDeveloperRoleToSystem: trueforhive, plus sanitizinginput_text-style parts and lone surrogates before the wire, would stop the failures at the source.
Asks
- Record the
hivecapability facts (rejectsdeveloper; rejects non-textcontent parts; rejects lone surrogates) so the request is normalized rather than refused. - Classify this class of upstream
invalid_request_errorpayload-shape 400 as request-local/target-local so a combo can fail over instead of ending the turn.
Note
I could not isolate the exact Received bad JSON request string with a synthetic body; it appears to be Hive's JSON-parser layer reporting the same class of body it rejects (the sibling messages above are deterministic). Happy to share raw request bodies/traces if useful.
Activity
github-actions commentedon Oct 1, 2026
Automated translation bookkeeping — detected language: English.
github-actions commentedon Oct 1, 2026
Issue closed: use an issue template
Thanks for taking the time to submit this issue. It was closed automatically because it was not opened with a recognized issue template (Bug report, Feature request, Documentation, or Provider compatibility). Freeform and API-opened issues cannot skip this check.
Please edit the issue to add:
See the Contributing guide for details.
Once the report passes the automated checks, it will be reopened automatically unless a maintainer has changed its state.