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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions