{"record":{"id":"f876f3d460d73c8b","repo":"deepset-ai/haystack","slug":"max-total-tokens-must-be-a-positive-number-of-to","errorCode":null,"errorMessage":"`max_total_tokens` must be a positive number of tokens, got {max_total_tokens}.","messagePattern":"`max_total_tokens` must be a positive number of tokens, got (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"haystack/hooks/budget/hooks.py","lineNumber":58,"sourceCode":"        hooks={\"before_llm\": [TokenBudgetHook(max_total_tokens=100_000)]},\n    )\n\n    result = agent.run(messages=[...])\n    ```\n    \"\"\"\n\n    allowed_hook_points = (\"before_llm\",)\n\n    def __init__(self, *, max_total_tokens: int, add_final_message: bool = False) -> None:\n        \"\"\"\n        Create a token budget hook.\n\n        :param max_total_tokens: Maximum cumulative token usage before the Agent is stopped.\n        :param add_final_message: Whether to append an assistant message explaining why the Agent stopped.\n        :raises ValueError: If `max_total_tokens` is less than 1.\n        \"\"\"\n        if max_total_tokens < 1:\n            raise ValueError(f\"`max_total_tokens` must be a positive number of tokens, got {max_total_tokens}.\")\n        self.max_total_tokens = max_total_tokens\n        self.add_final_message = add_final_message\n\n    def run(self, state: State) -> None:\n        \"\"\"\n        Stop the Agent if its cumulative token usage has reached the budget.\n\n        :param state: Agent state containing the cumulative token usage.\n        \"\"\"\n        usage = state.data.get(\"token_usage\") or {}\n        # Not every chat generator reports `total_tokens`, so fall back to summing the input and output keys across\n        # the known naming conventions.\n        total_tokens = _first_numeric(usage, (\"total_tokens\",))\n        if not total_tokens:\n            total_tokens = _first_numeric(usage, _INPUT_TOKEN_KEYS) + _first_numeric(usage, _OUTPUT_TOKEN_KEYS)\n        if total_tokens >= self.max_total_tokens:\n            logger.warning(\n                \"Agent reached its token budget of {max_total_tokens} ({total_tokens} used); requesting a stop.\",","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/hooks/budget/hooks.py#L40-L76","documentation":"WallClockTokenBudget (haystack/hooks/budget/hooks.py) requires max_total_tokens to be a positive integer of tokens. A value less than 1 (0, negative, or otherwise falsy-as-small) would make the Agent stop immediately or behave nonsensically, so __init__ raises this ValueError with the offending value.","triggerScenarios":"Instantiating WallClockTokenBudget-like budget hook with max_total_tokens=0, a negative number, or a value computed from an empty/failed config lookup (e.g. int(os.getenv('MAX_TOKENS', 0))).","commonSituations":"Environment variable for the budget missing so the default 0 is used; copying an example that left the placeholder at 0; a unit conversion bug producing a negative value.","solutions":["Pass a positive integer, e.g. WallClockTokenBudget(max_total_tokens=10000).","Fix the config/env lookup so the value defaults to a sensible positive number.","Validate/normalize before constructing: max(1, int(configured_value))."],"exampleFix":"// before\nbudget = WallClockTokenBudget(max_total_tokens=int(os.getenv('MAX_TOKENS', 0)))\n// after\nmax_tokens = int(os.getenv('MAX_TOKENS', '10000'))\nbudget = WallClockTokenBudget(max_total_tokens=max(1, max_tokens))","handlingStrategy":"validation","validationCode":"if not isinstance(max_total_tokens, int) or max_total_tokens < 1:\n    raise ValueError('max_total_tokens must be a positive integer')","typeGuard":"def is_positive_int(v: object) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v >= 1","tryCatchPattern":"try:\n    budget = WallClockTokenBudget(max_total_tokens=cfg['max_total_tokens'])\nexcept ValueError as e:\n    if 'max_total_tokens' in str(e):\n        budget = WallClockTokenBudget(max_total_tokens=10000)\n    else:\n        raise","preventionTips":["Never default the token budget to 0; use a sane positive default","Validate env/config values with int() and a lower bound before constructing","Use type annotations (max_total_tokens: int) and a type checker to catch bad inputs"],"tags":["python","agent","argument-validation","configuration"],"backgroundTag":"invalid-numeric-config","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}