windmill-labs/windmill · error

No response body for SSE stream

Error message

No response body for SSE stream

What it means

The Windmill CLI's `wmill app dev` command streams run/job updates from the backend via Server-Sent Events (`/jobs_u/getupdate_sse/<jobId>`). After the fetch succeeds (HTTP status OK and no auth-gateway challenge), it calls `response.body.getReader()`; if the response has no readable body it throws this error, because there is no stream to forward to the browser WebSocket.

Source

Thrown at cli/src/commands/app/dev.ts:1984

  const response = await fetch(sseUrl, {
    headers: {
      Accept: "text/event-stream",
      Authorization: `Bearer ${token}`,
      ...extraHeaders,
    },
  });

  await detectAuthGatewayChallenge(response, sseUrl);

  if (!response.ok) {
    throw new Error(
      `SSE request failed: ${response.status} ${response.statusText}`,
    );
  }

  const reader = response.body?.getReader();
  if (!reader) {
    throw new Error("No response body for SSE stream");
  }

  const decoder = new TextDecoder();
  let buffer = "";

  try {
    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() || "";

      for (const line of lines) {
        if (line.startsWith("data: ")) {
          const data = line.slice(6);
          try {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Check that the URL is reachable and returns a real `text/event-stream` response (curl -N the SSE URL with a Bearer token).
  2. Verify no proxy/auth gateway intercepts the response; check `detectAuthGatewayChallenge` output and instance base URL (`--baseUrl`).
  3. Upgrade the CLI runtime (Node/Deno/Bun) to a version with full streaming fetch support.
  4. Retry the `wmill app dev` command; if persistent, capture the raw response with curl and inspect headers/body.

Example fix

// defensive: report status when body is missing
const reader = response.body?.getReader();
if (!reader) {
  throw new Error(`No response body for SSE stream (status ${response.status}, content-type ${response.headers.get('content-type')})`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const res = await fetch(sseUrl, { headers: { Accept: 'text/event-stream', Authorization: `Bearer ${token}` } });
if (!res.ok || !res.body) throw new Error(`SSE unavailable: ${res.status}`);

Type guard

function hasBody(r: Response): r is Response & { body: ReadableStream } { return r.body !== null; }

Try / catch

try { await streamJobWithSSE(...) } catch (e) { if (String(e).includes('No response body')) fallbackToPolling(jobId); else throw e; }

Prevention

When it happens

Trigger: Calling the SSE endpoint on a server or fetch runtime that returns a null `response.body` — e.g. an unexpected HTTP method/result, a proxy that stripped or buffered the body, or a runtime whose fetch implementation does not expose a ReadableStream for streaming responses.

Common situations: Corporate proxies or auth gateways in front of the Windmill instance intercepting the event-stream request; misconfigured reverse proxy returning an empty 200; running the CLI in a Node/Deno version with limited streaming fetch support; a redirect to a login page that returns OK with an HTML body-less response.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/cda5e6f547f6a6c7. Report an issue: GitHub.