unslothai/unsloth · error · GenerationLengthError

The model reached the Max Tokens limit before producing a fi

Error message

The model reached the Max Tokens limit before producing a final answer. Increase Max Tokens or disable thinking, then retry.

What it means

GenerationLengthError is thrown when the stream terminated with finish_reason === "length" (Max Tokens hit) and the model emitted reasoning content but never produced any assistant-facing text — i.e. the entire token budget was consumed by thinking. The message tells the user to raise Max Tokens or disable thinking. It is a typed error class (chat-api.ts:82) so the UI can offer a targeted retry action.

Source

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

  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";
  let completed = false;
  // EOF without `[DONE]` or a finish_reason chunk means the stream was cut mid-generation.
  let sawTerminalSignal = false;
  let terminalFinishReason: string | null = null;
  let sawAssistantContent = false;
  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/);

View on GitHub (pinned to 203007d190)

Solutions

  1. Increase the Max Tokens setting for the request/model.
  2. Disable thinking/reasoning mode for this generation.
  3. If both are fixed by policy, surface the typed error and let the user retry with adjusted settings rather than retrying blindly.

Example fix

// before
payload.max_tokens = 1024; // reasoning eats it all

// after
payload.max_tokens = 8192;
// or: payload.reasoning_effort = 'none';
Defensive patterns

Strategy: validation

Validate before calling

// Before sending: budget for reasoning overhead
const isReasoning = modelSupportsThinking(payload.model);
if (isReasoning && (payload.max_tokens ?? 0) < 4096) {
  payload = { ...payload, max_tokens: Math.max(payload.max_tokens ?? 0, 4096) };
}

Type guard

export function isGenerationLengthError(e: unknown): e is GenerationLengthError {
  return e instanceof GenerationLengthError;
}

Try / catch

try { for await (const c of stream) render(c); }
catch (e) {
  if (isGenerationLengthError(e)) offerRetryWithHigherLimit();
  else throw e;
}

Prevention

When it happens

Trigger: A reasoning model with a low max_tokens setting: the reasoning channel fills the budget, finish_reason becomes 'length', sawAssistantContent stays false, and throwIfReasoningOnlyLength() fires at stream end (either [DONE] or clean EOF).

Common situations: Reasoning models (o-series / thinking modes) with max_tokens copied from a non-reasoning config; long chains of thought eating a 1-2k budget; users enabling thinking on a plan/model with a tight output cap.

Related errors


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