alibaba/nacos · error · Error

HTTP ${response.status}

Error message

HTTP ${response.status}

What it means

Thrown by the SSE streaming fetch helper when the server returns a non-2xx HTTP status (response.ok is false). The error fires before any stream reading begins, so no SSE data is consumed. It surfaces the raw status code with no response body, making diagnosis of 401/403/422/500 cases dependent on network inspection.

Source

Thrown at console-ui-next/src/lib/sse-utils.ts:95

  const controller = new AbortController();
  const token = getAccessToken();

  fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'text/event-stream',
      ...(token
        ? { Authorization: `Bearer ${token}`, AccessToken: token }
        : {}),
    },
    body: JSON.stringify(payload),
    signal: controller.signal,
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      const reader = response.body!.getReader();
      const decoder = new TextDecoder();
      let buffer = '';
      let currentEventType = 'message';
      let pendingData: T | null = null;

      const read = (): Promise<void> =>
        reader.read().then(({ done, value }) => {
          if (done) {
            onFinish?.();
            return;
          }

          buffer += decoder.decode(value, { stream: true });
          const lines = buffer.split('\n');
          buffer = lines.pop() || '';

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Check the status code value: 401/403 means refresh the auth token; 422 means fix the payload schema; 5xx means retry or contact backend.
  2. Inspect the response body via browser DevTools Network tab, since the error message discards it.
  3. For token-expiry, implement a token refresh interceptor before the SSE call and retry once.
  4. Add response body extraction in the helper so the thrown error carries server-side detail.

Example fix

// before
.then((response) => {
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }

// after
.then(async (response) => {
  if (!response.ok) {
    const detail = await response.text().catch(() => '');
    throw new Error(`HTTP ${response.status}: ${detail}`);
  }
Defensive patterns

Strategy: retry

Validate before calling

async function safeSse(url, payload, token) {
  const r = await fetch(url, { method:'POST', headers:{'Content-Type':'application/json', Authorization:`Bearer ${token}`}, body: JSON.stringify(payload) });
  if (r.status === 401 || r.status === 403) { throw new Error('AUTH_EXPIRED'); }
  if (!r.ok) { throw new Error(`HTTP ${r.status}: ${await r.text().catch(()=> '')}`); }
  return r;
}

Type guard

function isRetryableStatus(status: number): boolean {
  return status === 429 || status >= 500;
}

Try / catch

try { await streamSse(...); } catch (e) {
  if (/HTTP 401|HTTP 403/.test(e.message)) { await refreshToken(); /* retry once */ }
  else if (/HTTP 5\d\d/.test(e.message)) { scheduleRetry(); }
  else { showError(e.message); }
}

Prevention

When it happens

Trigger: The backend rejects the SSE request due to an expired or missing Bearer token (401/403), a malformed payload failing server-side validation (400/422), or a transient server error (500/502/503). The endpoint URL or path is wrong (404).

Common situations: Long-running chat/completion sessions where the token expires mid-session. Proxy or gateway (nginx) timeouts returning 504. CORS misconfiguration returning a 0 or opaque status. Request payload exceeding a body-size limit (413).

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/aa02b0b3e8708034. Report an issue: GitHub.