unslothai/unsloth · error

${label} did not report completion: the connection closed be

Error message

${label} did not report completion: the connection closed before the server's reply arrived. Check the model's status before retrying.

What it means

assertCompletedPaddedBody validates that a padded (non-streaming) response body is a non-empty, non-array object — the protocol's completion marker. An empty object, null, array, primitive, or empty body means the connection closed before the server's reply arrived, mirroring the backend check require_completed_padded_body in unsloth_cli/_inference.py. The label names which operation failed.

Source

Thrown at studio/frontend/src/features/chat/api/padded-response.ts:22

/**
 * `/api/inference/load` and `/unload` pad their body so a proxy cannot time the request
 * out, committing the 200 before the work finishes (`_tunnel_safe_json` in
 * studio/backend/routes/inference.py). A proxy giving up mid-pad leaves a 200 with an
 * empty or truncated body; accepting that reports an unfinished load as done. Only
 * these two routes commit that early, so only they require a payload; elsewhere an
 * empty body is by design. Mirrored by `require_completed_padded_body` in
 * unsloth_cli/_inference.py.
 */
export function assertCompletedPaddedBody(body: unknown, label: string): void {
  const complete =
    typeof body === "object" &&
    body !== null &&
    !Array.isArray(body) &&
    Object.keys(body).length > 0;
  if (complete) {
    return;
  }
  throw new Error(
    `${label} did not report completion: the connection closed before the server's reply arrived. Check the model's status before retrying.`,
  );
}

View on GitHub (pinned to 203007d190)

Solutions

  1. Check the model server's status/logs — the message explicitly says the reply never arrived, so the server side is the suspect.
  2. Look for proxy response-size/time limits truncating the body.
  3. Retry the request once the model is healthy (the error is safe to retry — no side effects).
  4. If it persists, verify the frontend and backend padding-protocol versions match (require_completed_padded_body mirror).
Defensive patterns

Strategy: retry

Validate before calling

import { assertCompletedPaddedBody } from './padded-response';
// Pre-flight the model is accepting requests before a long padded call
if (!(await modelHealthcheck())) throw new Error('Model not ready');

Type guard

function isPaddedBodyIncomplete(e: unknown): boolean {
  return e instanceof Error && e.message.includes('did not report completion');
}

Try / catch

try { assertCompletedPaddedBody(body, label); }
catch (e) {
  if (isPaddedBodyIncomplete(e) && attempt < 2) { await backoff(attempt); return requestAgain(); }
  throw e;
}

Prevention

When it happens

Trigger: Calling a padded/non-stream endpoint whose proxy or server returns an empty body (200 with no content, or truncated JSON parsed to null) — e.g. model server crashed after accepting the request, or a gateway timed out and returned an empty 200.

Common situations: Model server OOM/restart mid-inference; reverse proxy buffering and truncating long responses; connection killed after headers but before body; backend version drift where the padding protocol changed.

Understand the failure class

Related errors


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