NousResearch/hermes-agent · error · ValueError

Anthropic Messages adapter requires a positive max_tokens va

Error message

Anthropic Messages adapter requires a positive max_tokens value for model {model!r}; got {requested!r} and no model default resolved.

What it means

The Anthropic Messages adapter requires a positive max_tokens on every call. This ValueError fires when the caller passed a non-positive value (0/None/negative) AND _get_anthropic_max_output(model) resolved no positive default for that model name. The resolver deliberately does no context-window clamping so the positive-value contract stays independent of endpoint specifics.

Source

Thrown at agent/anthropic_adapter.py:258

    Prefers ``requested`` when it is a positive finite number; otherwise
    falls back to the model's output ceiling. Raises ``ValueError`` if no
    positive budget can be resolved (should not happen with current model
    table defaults, but guards against a future regression where
    ``_get_anthropic_max_output`` could return ``0``).

    Separately, callers apply a context-window clamp — this resolver does
    not, to keep the positive-value contract independent of endpoint
    specifics.

    Ported from openclaw/openclaw#66664 (resolveAnthropicMessagesMaxTokens).
    """
    resolved = _resolve_positive_anthropic_max_tokens(requested)
    if resolved is not None:
        return resolved
    fallback = _get_anthropic_max_output(model)
    if fallback > 0:
        return fallback
    raise ValueError(
        f"Anthropic Messages adapter requires a positive max_tokens value for "
        f"model {model!r}; got {requested!r} and no model default resolved."
    )


def _supports_adaptive_thinking(model: str) -> bool:
    """Return True for Claude models that use adaptive thinking (4.6+).

    Defaults *unknown* Claude models to adaptive (the modern contract) and
    only returns False for the explicit legacy list of older Claude families
    that require manual budget-based thinking. Non-Claude Anthropic-Messages
    models (minimax, qwen3, …) return False so they keep the manual path.

    Kimi / Moonshot models are the exception: their Anthropic-compatible
    endpoints implement the adaptive contract (``thinking.type="adaptive"``
    + ``output_config.effort``, including ``xhigh`` and ``display``).
    """
    if _model_name_is_kimi_family(model):

View on GitHub (pinned to c896c09c42)

Solutions

  1. Pass an explicit positive max_tokens (e.g. 16384) at the call site
  2. If 'use the model default' was intended, omit the value entirely rather than zeroing it
  3. Add or update the model's default in the max-output resolution table so the fallback is positive
  4. Upgrade to a release where the new model's default is catalogued

Example fix

# before
build_anthropic_request(messages=msgs, max_tokens=0)

# after
build_anthropic_request(messages=msgs, max_tokens=16384)
Defensive patterns

Strategy: validation

Validate before calling

def valid_max_tokens(value) -> bool:
    return isinstance(value, int) and not isinstance(value, bool) and value > 0

if max_tokens is not None:
    assert valid_max_tokens(max_tokens), (
        f"Anthropic Messages requires positive max_tokens, got {max_tokens!r}"
    )

Type guard

from typing import Any

def is_positive_int(value: Any) -> bool:
    """Narrows to a positive, non-bool integer usable as Anthropic max_tokens."""
    return isinstance(value, int) and not isinstance(value, bool) and value > 0

Try / catch

try:
    payload = build_anthropic_messages_request(messages, max_tokens=max_tokens)
except ValueError as e:
    if "positive max_tokens" in str(e):
        payload = build_anthropic_messages_request(messages, max_tokens=16384)
    else:
        raise

Prevention

When it happens

Trigger: Building/converting an Anthropic Messages request with max_tokens=0, None, or a negative number for a model that has no entry in the max-output table, so the fallback returns 0.

Common situations: A new or renamed Claude model not yet present in _get_anthropic_max_output's table while call-site code passes 0 meaning 'unlimited'; config sets max_tokens: 0 expecting a provider default; a caller copying chat-completions semantics where 0 can mean unset.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/79a435b8ece5f916. Report an issue: GitHub.