Skip to content

Why max_tokens Is Required in the Claude API

7 min read · updated August 11, 2026

A Messages request without max_tokens is rejected before anything is generated. Every other sampling parameter is optional; this one is not, and the reason has more to do with how your rate limit is computed than with generation.

The error

Omit the field and the API returns a 400 with an invalid_request_error naming it:

$ curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-sonnet-4-5-20250929",
      "messages": [{"role": "user", "content": "Hello"}]
    }'

HTTP/1.1 400 Bad Request

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "max_tokens: Field required"
  }
}

The fix is one line, and the rest of this page is about what to put in it:

{
  "model": "claude-sonnet-4-5-20250929",
  "max_tokens": 1024,
  "messages": [{"role": "user", "content": "Hello"}]
}

You will usually meet this from a hand-rolled HTTP client, from a request assembled from a template, or from code ported from an API where the parameter is optional. The official SDKs make it a required argument, so the Python and TypeScript clients fail at the type or signature level before a request is sent — which is why the error tends to surface in curl, in a serverless function building JSON by hand, or in a proxy that strips unknown fields.

The proxy case is worth calling out separately, because it produces the most confusing version of this failure. Code that works locally and fails in one environment, with a parameter the developer can see in their own request body, usually means something between the application and Anthropic is rewriting the body — a compatibility shim translating from another API’s schema, a gateway with an allow-list of fields, or a serialiser dropping keys whose value it considers empty. Check what leaves your process, not what you constructed.

Wording of the message string is not part of the API contract and has changed with validation-layer updates. Branch on the 400 status and error.type, not on the text. Field requirements are documented in Anthropic’s Messages API reference.

Why there is no default

The obvious reading is that Anthropic wants you to think about output length. That is part of it. The mechanical reason is that max_tokens is not only a stopping condition — it is a reservation, and the platform uses it before generation begins.

Anthropic’s rate limits include an output-tokens-per-minute bucket. Output length cannot be known in advance, so the platform has to estimate it at admission time, and the estimate it uses is derived from what you asked for. Your max_tokens is the number the system has to assume you might consume. Without it there is no figure to admit the request against.

It is also a capacity signal for scheduling: a request that might run for 32,000 tokens occupies a slot very differently from one capped at 200, and a server that knows which is which can pack work better. A default would make every request look like the worst case, which is exactly the outcome the next section is about.

That framing explains why the requirement has survived while other parameters acquired defaults. A default for temperature costs the platform nothing — it is applied at sampling time and affects one request. A default for max_tokens would have to be either small, in which case a large share of answers would be silently truncated for people who never set it, or large, in which case every unset request reserves worst-case capacity. Neither is a good default, so there is none, and the cost of that decision is a 400 the first time you write a request by hand.

Why the maximum is the wrong value

The tempting fix is to set max_tokens to the model’s documented maximum everywhere and never think about it again. It makes the error go away and it costs you throughput.

Because the reservation is what your output rate limit is charged against at admission, a request capped at 8,192 tokens that produces 40 tokens of output still had 8,192 tokens reserved against your bucket while it was in flight. Set that on a high-volume classification endpoint and you will hit 429s at a small fraction of the request rate you were expecting, with an actual output volume nowhere near your limit. The symptom is rate limiting that makes no sense against your usage graph.

A second cost is the context window. Input and output share the window, so a large reservation shrinks the space available for your prompt. A 190,000-token document with max_tokens at 32,000 against a 200,000-token window fails, and the error you get is about the prompt being too long — see the context window exceeded page, where this is a common cause of an error that looks like it is about something else.

A third is that it removes your only guard against a runaway generation. A model that begins repeating itself will keep going to the cap. The cap is what bounds the cost of that incident, and the incident is not hypothetical: a degenerate loop at the model maximum on a high-volume endpoint turns a fixed per-request cost into an unbounded one, and nothing else in the request stops it.

A fourth, less obvious, is latency. Nothing forces a model to use its cap, but a generous one removes a signal that the answer should be short, and time to complete scales directly with tokens produced. If a p95 latency target matters, the cap is one of the few hard levers you have over the tail — a request capped at 400 tokens cannot take as long as one capped at 8,192, whatever the model decides to do.

The other max_tokens error

Setting it too high is its own 400. Each model has a documented maximum output length, and they differ substantially across the range — the small fast models and the large ones do not share a ceiling. Exceeding it produces a message naming both numbers:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "max_tokens: 100000 > 8192, which is the maximum allowed number of output tokens for claude-3-5-sonnet-20241022"
  }
}

This is a useful error, because it tells you the actual ceiling for the exact model id you named, which is more reliable than any table — if you are unsure what a model’s output limit is, sending an absurdly large value and reading the rejection is a legitimate and instant way to find out, and it costs nothing because validation fails before generation. It is also the error to expect when you switch a configured model id to a smaller model without revisiting the cap that was set for the larger one. Note that some models have offered higher output limits behind a beta header, so the ceiling is not always a fixed property of the model id alone. Per-model output limits are covered on the maximum output tokens page.

Setting it properly

  1. Estimate from the longest acceptable answer, not the longest possible one. English runs roughly 0.75 words per token, so a 300-word answer is about 400 tokens. Double it for headroom and set 800, not 8,192.
  2. Set it per call site, not globally. A classifier returning one word and a report generator have nothing in common here. One constant in a config file is the usual mistake.
  3. Always check stop_reason. If it comes back as max_tokens, the answer was cut off mid-sentence and your cap is too low for that input. That is a signal to log, and to surface rather than silently store.
    if response.stop_reason == "max_tokens":
        log.warning("truncated", extra={"cap": MAX_OUT,
                                        "used": response.usage.output_tokens})
  4. Budget it against the window. Input plus max_tokens must fit. Compute the input side with count_tokens and subtract.
  5. Raise it for extended thinking. Thinking tokens are output tokens and are counted against this cap, so a thinking budget of 10,000 needs a max_tokens comfortably above it or the model has no room left to answer.