Wei-Shaw/sub2api · error
HTTP error! status: ${response.status}
Error message
HTTP error! status: ${response.status} What it means
In frontend/src/components/admin/account/AccountTestModal.vue:896 (the admin variant of the test modal), the streaming fetch checks response.ok and throws `HTTP error! status: ${response.status}` for any non-2xx. This variant sends an ADMIN_UI_REQUEST_HEADER: '1' marker, so failures commonly relate to admin authentication/authorization rather than the model itself. The response body's error detail is discarded.
Source
Thrown at frontend/src/components/admin/account/AccountTestModal.vue:896
}
// Use the configured API base; EventSource does not support POST.
const url = buildApiUrl(`/admin/accounts/${props.account.id}/test`)
// Use fetch with streaming for SSE since EventSource doesn't support POST
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${localStorage.getItem('auth_token')}`,
'Content-Type': 'application/json',
[ADMIN_UI_REQUEST_HEADER]: '1'
},
body: JSON.stringify(requestBody),
signal: abortController.signal
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const reader = response.body?.getReader()
if (!reader) {
throw new Error(t('admin.accounts.grok.noResponseBody'))
}
const decoder = new TextDecoder()
let buffer = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
buffer += decoder.decode(value, { stream: true })
const lines = buffer.split('\n')
buffer = lines.pop() || ''
View on GitHub (pinned to 073e92d171)
Solutions
- Parse the response body for an error message before throwing, mirroring the i18n approach used for noResponseBody.
- On 401/403, redirect to admin re-login and stop the spinner cleanly.
- Ensure ADMIN_UI_REQUEST_HEADER is actually set on this request in the deployed environment (check proxy header forwarding).
- Add specific messages per status (401/403/429/5xx) instead of the generic template.
Example fix
// before
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
// after
if (!response.ok) {
const body = await response.json().catch(() => null)
const msg = body?.error?.message || body?.message
if (response.status === 401 || response.status === 403) {
await reauthenticateAdmin()
throw new Error(t('admin.accounts.grok.unauthorized'))
}
throw new Error(msg ? `${msg} (HTTP ${response.status})` : t('admin.accounts.grok.httpError', { status: response.status }))
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!localStorage.getItem('auth_token')) { redirectToAdminLogin(); } // before opening the admin test modal Try / catch
try { await adminStreamTest(); }
catch (e) {
const status = String(e?.message).match(/status: (\d+)$/)?.[1];
if (status === '401' || status === '403') { await reauthenticateAdmin(); return; }
showError(parseDetail(e));
} Prevention
- Parse the response JSON error body before throwing; keep the generic string only as fallback
- Verify ADMIN_UI_REQUEST_HEADER survives any reverse proxy
- Handle 401/403 with a re-login flow instead of a toast
When it happens
Trigger: POST to the admin account-test URL returns 401 (admin token expired), 403 (non-admin user or missing ADMIN_UI_REQUEST_HEADER), 400 (invalid requestBody/model_id), or 5xx (upstream provider failure). The thrown message contains only the status number.
Common situations: Admin session expiring while the modal is open; the admin request header stripped by a proxy or missing in a custom deployment; testing an account whose upstream key is dead; gateway timeout on slow model responses (504).
Related errors
- HTTP error! status: ${response.status}
- admin.accounts.grok.noResponseBody
- keyUsage.queryFailed
- No response body
- admin.backup.actions.downloadFailed
AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15).
Data as JSON: /api/errors/b9b9d2641a149817.
Report an issue: GitHub.