unslothai/unsloth · error · StreamInterruptedError

Response interrupted: the connection dropped before the mode

Error message

Response interrupted: the connection dropped before the model finished. Use Retry to regenerate.

What it means

StreamInterruptedError is thrown when the SSE reader hits EOF (done === true) without ever seeing a terminal signal — neither the [DONE] sentinel nor a chunk with a finish_reason. The connection closed mid-generation, so the partial transcript is incomplete. The message directs the user to Retry to regenerate.

Source

Thrown at studio/frontend/src/features/chat/api/chat-api.ts:1346

  let sawReasoningContent = false;

  const throwIfReasoningOnlyLength = () => {
    if (
      terminalFinishReason === "length" &&
      sawReasoningContent &&
      !sawAssistantContent
    ) {
      throw new GenerationLengthError();
    }
  };

  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        completed = true;
        if (!sawTerminalSignal) {
          throw new StreamInterruptedError();
        }
        throwIfReasoningOnlyLength();
        break;
      }

      buffer += decoder.decode(value, { stream: true });

      let separatorIndex = buffer.search(/\r?\n\r?\n/);
      while (separatorIndex >= 0) {
        const rawEvent = buffer.slice(0, separatorIndex);
        const separatorLength = buffer[separatorIndex] === "\r" ? 4 : 2;
        buffer = buffer.slice(separatorIndex + separatorLength);

        const dataLines = parseSseEvent(rawEvent);
        if (dataLines.length === 0) {
          separatorIndex = buffer.search(/\r?\n\r?\n/);
          continue;
        }

View on GitHub (pinned to 203007d190)

Solutions

  1. Retry the generation — the UI Retry action re-issues the request.
  2. Raise intermediary timeouts (proxy_read_timeout, LB idle timeout) for /v1/chat/completions.
  3. If it reproduces consistently at the same elapsed time, find and raise the timeout that matches that duration.
  4. Check inference-server logs for OOM/crash mid-generation.
Defensive patterns

Strategy: retry

Type guard

export function isStreamInterruptedError(e: unknown): e is StreamInterruptedError {
  return e instanceof StreamInterruptedError;
}

Try / catch

try { for await (const c of stream) render(c); }
catch (e) {
  if (isStreamInterruptedError(e) && attempt < 2) { await backoff(attempt); return regenerate(); }
  throw e;
}

Prevention

When it happens

Trigger: Network drop, proxy timeout, server crash, or load-balancer idle kill between chunks: reader.read() resolves done=true with sawTerminalSignal still false.

Common situations: Long generations exceeding proxy/gateway timeouts (nginx proxy_read_timeout, ALB idle timeout); flaky mobile connections; inference server OOM or restart mid-stream; VPN reconnects.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/6d363dd2ea25a0ca. Report an issue: GitHub.