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

  1. 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.
  2. For 401, route the user to re-login instead of showing a raw error.
  3. For 429/5xx, add retry-with-backoff or a clear 'provider temporarily unavailable' message.
  4. 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

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


AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15). Data as JSON: /api/errors/84f7fcb0016eccf2. Report an issue: GitHub.