iflytek/astron-agent · error · Error

Failed to establish SSE connection

Error message

Failed to establish SSE connection

What it means

The document page uses an SSE client (fetch-event-source style) whose `onopen` callback throws 'Failed to establish SSE connection' whenever the HTTP response is not ok (response.ok false, i.e. status outside 200-299). The library surfaces this thrown error through the returned promise, so the caller's catch handles a failed EventSource handshake.

Solutions

  1. Inspect response.status in onopen and throw a message including the status code for diagnosis.
  2. Refresh/re-obtain the auth token and retry the connection with updated headers.
  3. Verify the SSE endpoint URL and that the backend service and gateway route are healthy.
  4. Add abort + retry with backoff for transient 5xx failures (the signal is already wired via controllerRef).

Example fix

// before
async onopen(response) {
  if (response.ok) {
    setLoading(false);
  } else {
    throw new Error(`Failed to establish SSE connection`);
  }
}

// after
async onopen(response) {
  if (response.ok) {
    setLoading(false);
    return;
  }
  const body = await response.text().catch(() => '');
  throw new Error(`SSE connection failed: ${response.status} ${body.slice(0, 200)}`);
}
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(sseUrl, { method: 'HEAD', headers });
if (!res.ok) {
  console.error('SSE endpoint unhealthy', res.status);
  return; // or refresh token first
}

Type guard

function isOkResponse(r: Response): boolean {
  return r.status >= 200 && r.status < 300;
}

Try / catch

try {
  await fetchEventSource(url, { onopen, ...opts });
} catch (e) {
  if (String(e).includes('Failed to establish SSE connection')) {
    await refreshToken();
    scheduleRetryWithBackoff();
  }
  setLoading(false);
}

Prevention

When it happens

Trigger: The SSE endpoint returns 401/403 (expired token in `headers`), 404 (wrong document/conversation URL), 500 from the backend, or a gateway 502/504 — any non-ok status triggers the throw inside onopen.

Common situations: Session token expired mid-use; auth header not attached; backend service down behind nginx; CORS preflight failing so fetch gets opaque/failed response; proxy timeout on long-lived SSE endpoints.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/aefba65d69ee7371. Report an issue: GitHub.

Appendix: source

Thrown at console/frontend/src/pages/resource-management/knowledge-detail/document-page/hooks/use-document-page.tsx:188

      // 获取访问令牌
      const accessToken = localStorage.getItem('accessToken');
      const headers: Record<string, string> = {};
      if (accessToken) {
        headers['Authorization'] = `Bearer ${accessToken}`;
      }

      await fetchEventSource(
        `${getFixedUrl('/file/search-file')}?fileName=${encodeURIComponent(
          searchValue
        )}&repoId=${repoId}&pid=${parentId}&tag=${tag}`,
        {
          signal: controllerRef?.current?.signal,
          headers,
          async onopen(response) {
            if (response.ok) {
              setLoading(false);
            } else {
              throw new Error(`Failed to establish SSE connection`);
            }
          },
          onmessage(event) {
            if (event.data === 'bye') {
              controllerRef.current?.abort();
              controllerRef.current = null;
              return;
            }
            const item = JSON.parse(event.data);
            item.type = fileType(item);
            const regexPattern = new RegExp(searchValue, 'gi');
            item.name = item.name.replaceAll(
              regexPattern,
              '<span style="color:#6356EA;font-weight:600;display:inline-block;padding:4px 0px;background:#dee2f9">$&</span>'
            );

            setSearchData(resultList => [...resultList, item]);
          },

View on GitHub (pinned to 5e758547a8)