Skip to content

validate_max_tokens is Base-only and accepts bool: Solana paid paths take any value, including 10**12 #31

Description

@VickyXAI

Two gaps in validate_max_tokens, both pre-existing and both reachable on paid requests. Neither was introduced by #27, but #27 made the guard's rationale explicit without extending it.

1. The Solana client never calls the guard

validate_max_tokens is called from blockrun_llm/client.py only — lines 610, 734, 2341, 2428.

blockrun_llm/solana_client.py imports validate_api_url, validate_image_quality and validate_video_input_type from .validation, but not validate_max_tokens. It puts the caller's value straight into paid request bodies:

  • solana_client.py:701body: Dict[str, Any] = {"model": model, "messages": messages, "max_tokens": max_tokens}
  • solana_client.py:805"max_tokens": max_tokens,
  • solana_client.py:2975 — same as 701 (async)
  • solana_client.py:3027 — same as 805 (async)

So max_tokens=2_000_000 raises ValueError on Base and is signed and sent on Solana. Whatever the bound means, it is not an SDK-wide invariant.

This matters more than it looks, because the gateway does not reject an over-ceiling max_tokens — it clamps to the model ceiling and quotes payment for the clamped value (measured against the live 402 leg 2026-07-21: claude-opus-4.8 sent 262144 and 1000000 both quote the 128000 price; gpt-5.2 sent 1e12 returns a quote, not a 400). There is no server-side rejection behind the missing client-side guard.

2. bool passes the integer check

validation.py:244 is if not isinstance(max_tokens, int):. bool is an int subclass, so:

>>> from blockrun_llm.validation import validate_max_tokens
>>> validate_max_tokens(True)   # no error

The wire body then carries "max_tokens": true. A stray True — from a flag threaded into the wrong keyword, say — is not a token count and should fail locally like any other typo.

Suggested fix

  • Import and call validate_max_tokens(max_tokens) on the four Solana chat paths, so both chains share one bound. If Solana is meant to opt out, say so in a comment — right now the omission reads as an oversight.
  • Reject bool explicitly: check isinstance(max_tokens, bool) before the int check.
  • Both want tests; tests/unit/test_validation.py already has the boundary cases to model them on.

Found during /review of #27.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions