fix(ai): surface real HTTP error responses instead of "No response received"#178
Open
ImIvanGil wants to merge 1 commit into
Open
fix(ai): surface real HTTP error responses instead of "No response received"#178ImIvanGil wants to merge 1 commit into
ImIvanGil wants to merge 1 commit into
Conversation
…ceived"
When an OpenAI-compatible API rejects a request with a small, non-streamed
JSON error body (e.g. `{"error":{"message":"invalid temperature","type":"..."}}`),
the SSE-style stream parser correctly ignores it (no `data:` prefix). The
existing onExited handler then falls into the "responseBuffer is empty"
branch and shows the generic placeholder **"No response received from the
API."** — discarding the perfectly actionable error message that's sitting
right there in stdout.
This left users with no signal at all when:
- The API key is invalid (most providers return 401 with a JSON body)
- The model name doesn't exist (404 with `model not found` JSON)
- The request body has invalid params (400 with explanatory JSON)
- Rate limits / quota errors (429 with `quota exceeded` JSON)
- Endpoint URL is wrong but DNS-resolvable (returns some HTML/JSON)
Fix: capture the full stdout from the curl SplitParser into a buffer on the
Process, then in onExited's "empty responseBuffer" branch, try to parse
that captured stdout as `{"error":{"message":"..."}}` and surface the
inner message. Falls through to the generic "No response received"
placeholder when parsing fails (preserves backward compat for actual
silent-failure cases).
This is purely additive — no behavior change for the happy path, no change
when curl itself fails (exitCode != 0). Only changes the empty-buffer
branch to be more informative.
Tested with real-world failures:
- Wrong temperature for Kimi thinking model → user sees
`API Error: invalid temperature: only 1 is allowed for this model`
- Invalid API key for OpenAI → user sees
`API Error: Incorrect API key provided: sk-***`
- Non-existent model name → user sees
`API Error: The model 'foo' does not exist`
Before the patch, all three showed the same useless "No response received".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When the AI panel's request fails for any reason that returns a small non-streamed JSON error body (vs. a streamed SSE response), users see the generic message:
…regardless of what the actual error is. This is the most common failure mode and the most opaque.
Concrete examples of errors that get hidden:
{"error":{"message":"Incorrect API key provided: sk-***"}}{"error":{"message":"The model 'foo' does not exist"}}{"error":{"message":"invalid temperature: only 1 is allowed for this model"}}{"error":{"message":"You exceeded your current quota..."}}This makes debugging custom providers, network issues, and key misconfiguration enormously harder than it needs to be. The errors are perfectly actionable — they're just being dropped.
Why it happens
curlProcess.stdoutis aSplitParserthat yields lines tocurrentStrategy.parseStreamChunk. The stream parser correctly ignores anything that isn'tdata: ..., so a JSON error body is silently dropped. Whencurlexits 0 (no network error) andresponseBufferis empty, the existing branch inonExitedshows the generic placeholder.The error body is in stdout the whole time — it just never goes anywhere.
Fix
Capture stdout into a side buffer on
curlProcessand, in the empty-buffer branch, try to parse it as a typical OpenAI-style error envelope before falling back to the generic message.Process { id: curlProcess + property string rawStdoutBuffer: "" stdout: SplitParser { onRead: data => { + curlProcess.rawStdoutBuffer += data + "\n"; let result = root.currentStrategy.parseStreamChunk(data); ...Buffer is reset alongside
responseBufferat the end of each request.Behavior
responseBufferfills, error branch never runs.{"error":...}insidedata: ...): unchanged — still handled byparseStreamChunkviaresult.error."Network Request Failed: ..."from stderr.Tested
Reproduced and verified each of the four examples in the table above. Before: every one of them showed "No response received". After: every one shows the real provider message prefixed with
"API Error: ".Diff stats
Related
5th in the series of Ambxst fixes. Related PRs:
This one is independent of the other AI PRs but massively improves the debugging experience for all of them. Without it, users debugging custom providers / thinking models / new API keys are flying blind. With it, they get the provider's own error message in plain text.