Wei-Shaw/sub2api · error
HTTP error! status: ${response.status}
Error message
HTTP error! status: ${response.status} What it means
In frontend/src/components/account/AccountTestModal.vue:440, a fetch() to the account-test streaming endpoint checks response.ok; any non-2xx status throws a generic `HTTP error! status: ${response.status}`. Because the response body (which the API uses for error detail) is discarded, the operator only learns the status code. This is the account-owner (non-admin) test modal.
Source
Thrown at frontend/src/components/account/AccountTestModal.vue:440
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'
},
body: JSON.stringify({
model_id: selectedModelId.value,
prompt: supportsImageTest.value ? testPrompt.value.trim() : '',
mode: isOpenAIAccount.value ? testMode.value : 'default'
}),
signal: abortController.signal
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const reader = response.body?.getReader()
if (!reader) {
throw new Error('No response body')
}
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
- Read the error body before throwing: `const detail = await response.text()` and include it in the thrown Error so the real API message is shown.
- For 401, route the user to re-login instead of showing a raw error.
- For 429/5xx, add retry-with-backoff or a clear 'provider temporarily unavailable' message.
- Verify auth_token exists in localStorage and is still valid before opening the modal.
Example fix
// before
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
// after
if (!response.ok) {
const text = await response.text().catch(() => '')
let detail = text
try { detail = JSON.parse(text)?.error?.message || text } catch {}
throw new Error(detail ? `${detail} (HTTP ${response.status})` : `HTTP error! status: ${response.status}`)
} Defensive patterns
Strategy: try-catch
Try / catch
try { await streamTest(); }
catch (e) {
const m = String(e?.message);
const status = m.match(/status: (\d+)$/)?.[1];
if (status === '401') { await relogin(); return; }
showError(m);
} Prevention
- Always read response body text before throwing so server error detail is not discarded
- Check localStorage auth_token presence/freshness before starting the test
- Map 401/403/429/5xx to distinct user-facing messages
When it happens
Trigger: POST to the model test endpoint with a Bearer token from localStorage returns 401 (expired token), 403 (no permission for that model_id), 400 (empty/invalid model_id or prompt), 429 (rate limit), or 502/504 (upstream provider failing). The thrown error surfaces the numeric status only.
Common situations: Testing an account whose API key was revoked; selecting a model the account tier cannot access; expired localStorage auth_token after long idle; upstream OpenAI-compatible endpoint down; abort signal racing a 499-style disconnect.
Related errors
- HTTP error! status: ${response.status}
- keyUsage.queryFailed
- No response body
- admin.accounts.grok.noResponseBody
- Passkeys are not supported by this browser
AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15).
Data as JSON: /api/errors/84f7fcb0016eccf2.
Report an issue: GitHub.