This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 309ff0379 fix(web): preserve AI chat HTTP error messages (#1967)
309ff0379 is described below
commit 309ff03793aa9d092f0a1a25a956385817e54931
Author: coder999o <[email protected]>
AuthorDate: Wed Aug 19 11:49:16 2026 +0800
fix(web): preserve AI chat HTTP error messages (#1967)
---
web/src/api/ai.test.ts | 24 ++++++++++++++++++++++++
web/src/api/ai.ts | 32 +++++++++++++++++++++++++++++++-
2 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/web/src/api/ai.test.ts b/web/src/api/ai.test.ts
index 64beff97c..9ca698287 100644
--- a/web/src/api/ai.test.ts
+++ b/web/src/api/ai.test.ts
@@ -180,6 +180,30 @@ describe('AI API', () => {
status: 400,
} satisfies Partial<AiStreamError>);
});
+
+ it('throws backend error messages from failed HTTP responses', async () =>
{
+ vi.stubGlobal(
+ 'fetch',
+ vi.fn().mockResolvedValue(
+ new Response(
+ JSON.stringify({
+ code: 400,
+ message: 'Chat request is required',
+ data: null,
+ }),
+ { status: 400, statusText: 'Bad Request' },
+ ),
+ ),
+ );
+
+ await expect(
+ chatStream({ message: '', mode: 'chat', model: 'stub' }, vi.fn()),
+ ).rejects.toMatchObject({
+ name: 'AiStreamError',
+ message: 'Chat request is required',
+ status: 400,
+ } satisfies Partial<AiStreamError>);
+ });
});
describe('executeAiCommand', () => {
diff --git a/web/src/api/ai.ts b/web/src/api/ai.ts
index 3a203e43a..8044adc53 100644
--- a/web/src/api/ai.ts
+++ b/web/src/api/ai.ts
@@ -110,6 +110,33 @@ function parseStreamError(payload: string): AiStreamError {
}
}
+async function parseHttpError(response: Response): Promise<AiStreamError> {
+ const fallback = response.statusText || `HTTP ${response.status}`;
+ try {
+ const payload = await response.text();
+ if (!payload.trim()) {
+ return new AiStreamError(
+ `AI chat failed: ${fallback}`,
+ undefined,
+ undefined,
+ response.status,
+ );
+ }
+ try {
+ const parsed = JSON.parse(payload) as AiStreamPayload;
+ const message = typeof parsed.message === 'string' ? parsed.message :
payload;
+ const code = typeof parsed.code === 'string' ? parsed.code : undefined;
+ const hint = typeof parsed.hint === 'string' ? parsed.hint : undefined;
+ const status = typeof parsed.status === 'number' ? parsed.status :
response.status;
+ return new AiStreamError(message, code, hint, status);
+ } catch {
+ return new AiStreamError(payload, undefined, undefined, response.status);
+ }
+ } catch {
+ return new AiStreamError(`AI chat failed: ${fallback}`, undefined,
undefined, response.status);
+ }
+}
+
function emitEvent(
event: string,
onChunk: (text: string) => void,
@@ -170,7 +197,10 @@ export async function chatStream(
signal,
});
- if (!response.ok || !response.body) {
+ if (!response.ok) {
+ throw await parseHttpError(response);
+ }
+ if (!response.body) {
throw new Error(`AI chat failed: ${response.statusText}`);
}