Ollama output cut off? Check stop reasons and token limits

ollamatroubleshootinglocal-llmtutorial

TL;DR: Save the final native Ollama response before raising limits. An output cap, a stop sequence, and a disconnected stream need different fixes. Increase the output budget only after confirming which boundary ended the request, then validate the actual answer separately.

What you’ll be able to do:

  • Separate a completed generation from an interrupted HTTP stream.
  • Inspect output limits and custom stop patterns without replacing the model.
  • Set a bounded retry policy that avoids repeatedly generating the same incomplete answer.

Honest take: A larger GPU will not fix a client that throws away the final response.

What does a cut-off Ollama answer actually prove?

An answer ending halfway through a sentence proves that the visible answer is incomplete. It does not identify the cause. Begin with the response envelope, then inspect the model configuration, and only then consider memory pressure.

The official generate API, checked November 8, 2026, exposes completion information alongside generated text. The chat API uses a different location for the answer. Keep those contracts separate when debugging a custom client.

EvidenceWhat it tells youFirst action
No final done: true recordCompletion was not establishedInspect the connection and client parser
Final response reports lengthA generation length boundary was reportedInspect the requested output budget
Final response reports stopGeneration stopped, without proving task successInspect stop patterns and answer validity
JSON response contains errorThe request failedRead that error before retrying
Complete raw answer, shortened UI answerDisplay or adapter path differsCompare raw and displayed text

Ollama upstream at commit d63b702609c4 maps its internal stop and length reasons to these strings. The routes copy the completion reason into native responses. This is a source-code check, not a claim that every installed backend was tested.

Treat unknown reasons as unknown. A client should preserve new server fields rather than silently turning every outcome into “success.” This matters when you update the server independently of the application.

The diagnostic below uses synthetic response fixtures. It does not claim a model inference run, a GPU measurement, or a particular model’s ability to finish a task.

How do you capture the answer without a streaming parser?

Temporarily disable streaming and write one native response to a file. This removes the browser and incremental JSON handling from the first comparison. Use an exact model you already installed; the placeholder is deliberately not a download recommendation.

ollama --version
ollama list
curl --fail-with-body --silent --show-error \
  http://localhost:11434/api/generate \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "YOUR_INSTALLED_MODEL",
    "prompt": "Write a short explanation of why backups need a restore test.",
    "stream": false,
    "options": {"num_predict": 128}
  }' > response.json

The output budget of 128 is an example setting for this diagnostic, not a recommended universal cap. The Modelfile parameter reference defines num_predict as the generation token maximum. A token is not a word, a character, or a line of code.

Inspect the HTTP exit status as well as the saved body. With --fail-with-body, curl can save useful server error text while still returning a failure status. Do not feed an error body into a success-only answer extractor.

If the raw response contains the whole answer while your application displays less, leave the server limits alone. Compare adapter response extraction, browser state updates, and any application output-length cap. Changing a server parameter would only obscure the evidence.

Can a small checker distinguish the failure classes?

Yes, a conservative checker can classify the response evidence without claiming the answer is correct. Save this standard-library helper as check_completion.py:

import json
import sys


def classify(data):
    if not isinstance(data, dict):
        raise ValueError("expected a native response object")
    if data.get("error"):
        raise ValueError("server error: " + str(data["error"]))
    if data.get("done") is not True:
        raise ValueError("missing final completion marker")
    reason = data.get("done_reason")
    if reason == "length":
        return "OUTPUT_LIMIT: inspect num_predict and task size"
    if reason == "stop":
        return "STOPPED: inspect stop patterns and validate the answer"
    return "UNKNOWN: preserve response and inspect server version"


if __name__ == "__main__":
    try:
        with open(sys.argv[1], encoding="utf-8") as handle:
            print(classify(json.load(handle)))
    except (ValueError, OSError, IndexError) as exc:
        raise SystemExit(str(exc))

Create an explicitly synthetic example and run it:

printf '%s\n' '{"done":true,"done_reason":"length"}' > fixture.json
python3 check_completion.py fixture.json

Expected output:

OUTPUT_LIMIT: inspect num_predict and task size

Our local fixture check on November 8 reproduced missing final completion marker when done was false. Keeping that rejection, rather than accepting a partial response, is the fix demonstrated here. The fixtures also exercise stop, length, server-error, unknown-reason, and non-object cases. They test the checker, not Ollama’s model execution.

Do not infer a length limit just because eval_count looks close to a familiar number. Preserve the exact request, the completion reason, and the installed server version. Different execution backends can expose different details, so the response is evidence to inspect rather than a promise that every backend emits the same vocabulary forever.

Why can a stop sequence end a perfectly valid sentence early?

A custom stop pattern tells generation to stop when that pattern is encountered. The official Modelfile reference permits multiple stop parameters. A short or ordinary-looking pattern can therefore end text earlier than the application expects.

Inspect the model configuration before changing it:

ollama show YOUR_INSTALLED_MODEL --modelfile

Look for custom PARAMETER stop entries and any output budget pinned in your own configuration. Also inspect the request your application sends: an adapter may supply options that were absent in your manual curl test.

Do not delete every stop token from an inherited chat template. Some are part of the model’s expected turn boundaries. Start by removing only a custom override you added, in a separate experiment, and repeat the same benign prompt. Preserve the original configuration so the comparison stays reversible.

A stop completion also occurs when the model chooses to finish. It does not mean a custom pattern definitely caused the cutoff. If the model simply writes a short answer, changing a stop list may do nothing. Ask for a bounded, explicit deliverable and validate whether it contains the required parts.

How do you distinguish an output cap from a context limit?

An output cap controls generated tokens; the context setting controls the working context available to the model. Increasing one is not a reliable substitute for configuring the other.

A useful diagnostic experiment changes only the requested output budget while holding the prompt, model, and other options constant. For example, compare a chosen cap of 128 with a chosen cap of 256. These values are experimental settings, not measured recommendations. If the recorded reason changes and the complete task now validates, you have useful evidence about that request.

If the input itself is being lost, use the separate Ollama prompt truncation checklist. That is an input-window problem. A response ending halfway through a generated function is a different symptom, even though both can appear in the same application.

Larger working contexts can increase memory demand. Before treating additional VRAM as the answer, establish that the intended context and model actually fit your workload. The VRAM calculator is a planning aid; it does not replace observing your real process. This article does not supply a universal bytes-per-token estimate because the model architecture and cache configuration matter.

What if the connection closes before the final record?

A stream without its final completion marker must remain incomplete in your application state. The official streaming documentation describes newline-delimited JSON for native streaming responses. Parse complete records and retain the final one, including fields beyond the answer fragment.

A network EOF is not equivalent to a successful model stop. Log whether the client canceled the request, a timeout fired, or an intermediary closed the connection. If the non-streaming reproduction completes but the streaming path fails, examine the application and transport path before changing the model.

The NDJSON parsing guide covers joining native stream fragments. For /api/generate, visible text is in response; for /api/chat, it is in message.content. Mixing those extraction rules can produce an empty or incomplete display even when the response is valid.

Avoid automatic retries that overwrite the first failure. Keep the original request ID, attempt number, and partial output. A second request is a new generation; it does not prove the first transport problem disappeared or that the second answer is semantically equivalent.

How should you budget a retry before buying hardware?

Reserve retries for a specific diagnosis. If a response reports a length boundary, either shorten the requested deliverable or raise its output budget once within a declared maximum. If the connection failed, inspect that path. If a completed answer fails your parser, use the structured-output validation guide before rerunning the whole task.

Suppose your policy allows two attempts with output caps of 128 and 256 tokens. The sum of the selected caps is 384 tokens. That arithmetic is a hypothetical budget ceiling for those settings, not actual token usage, a throughput measurement, or a dollar estimate. Record actual usage from the responses instead of reporting the cap sum as consumption.

For long code output, request one coherent unit at a time with explicit filenames and acceptance checks. Blindly asking “continue” can duplicate text or introduce a different implementation. Appending two plausible fragments does not establish that the resulting program works.

Honest take

Keep the final response, classify the stopping evidence, and validate the deliverable before increasing budgets. This procedure needs Python and your existing local server; it requires no paid API or new GPU. Its limit is equally clear: response inspection cannot measure answer quality, prove a model’s reasoning, or diagnose every backend memory failure.

Sources

Official sources checked November 8, 2026:

Last updated November 8, 2026. Software behavior and model support change; verify your installed version before changing configuration or purchasing hardware.

Was this article helpful?

Get the numbers before you buy

New GPU and mini-PC benchmarks, VRAM thresholds, and price checks — sent when there's something worth acting on, not on a schedule. No spam, unsubscribe anytime.