continuedev/continue · error · Error

non-200 response body: ${await response.text()}

Error message

non-200 response body: ${await response.text()}

What it means

streamResponse throws the response body text when the HTTP status is not 200 (and not 499, which signals client cancellation and returns silently). The body text typically carries the server's error message.

Source

Thrown at packages/fetch/src/stream.ts:18

export async function* toAsyncIterable(
  nodeReadable: NodeJS.ReadableStream,
): AsyncGenerator<Uint8Array> {
  for await (const chunk of nodeReadable) {
    // @ts-ignore
    yield chunk as Uint8Array;
  }
}

export async function* streamResponse(
  response: Response,
): AsyncGenerator<string> {
  if (response.status === 499) {
    return; // In case of client-side cancellation, just return
  }

  if (response.status !== 200) {
    throw new Error(await response.text());
  }

  if (!response.body) {
    throw new Error("No response body returned.");
  }

  // Get the major version of Node.js
  const nodeMajorVersion = parseInt(process.versions.node.split(".")[0], 10);
  let chunks = 0;

  try {
    if (nodeMajorVersion >= 20) {
      // Use the new API for Node 20 and above
      const stream = (ReadableStream as any).from(response.body);
      for await (const chunk of stream.pipeThrough(
        new TextDecoderStream("utf-8"),
      )) {
        yield chunk;

View on GitHub (pinned to 5522c6f44c)

Solutions

  1. Inspect status before streaming: if (response.status !== 200) handle error with status and body
  2. Fix auth/endpoint issues indicated by the status code (401 → API key, 429 → backoff, 404 → URL)
  3. Retry with exponential backoff for 429/5xx
  4. Log response.headers like 'x-ratelimit-*' to diagnose limits

Example fix

// before
const stream = streamSse(response);

// after
if (response.status !== 200) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const stream = streamSse(response);
Defensive patterns

Strategy: try-catch

Validate before calling

if (response.status !== 200) { const text = await response.text(); throw Object.assign(new Error(text), { status: response.status }); }

Try / catch

try { for await (const c of streamSse(response)) {} } catch (e) { if (e.message.includes('status')) {} /* handle */ }

Prevention

When it happens

Trigger: Any streamed request (streamSse/streamJSON) whose response has status 400/401/403/404/429/500 etc.; the awaited response.text() becomes the error message.

Common situations: Expired or wrong API keys (401), hitting rate limits (429), wrong endpoint paths (404), or upstream server errors (500) during chat completion streaming.

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 continuedev/continue@5522c6f44c (2026-08-27). Data as JSON: /api/errors/202281a1ebc1b2e0. Report an issue: GitHub.