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.

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.

Appendix: 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)