{"record":{"id":"4991ac4376d006f7","repo":"BerriAI/litellm","slug":"tools-or-tool-choice-cannot-be-set-if-using-text","errorCode":null,"errorMessage":"tools or tool_choice cannot be set if using text","messagePattern":"tools or tool_choice cannot be set if using text","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/token_counter.py","lineNumber":381,"sourceCode":"\n    #########################################################\n    # Flag to disable token counter\n    # We've gotten reports of this consuming CPU cycles,\n    # exposing this flag to allow users to disable\n    # it to confirm if this is indeed the issue\n    #########################################################\n    if litellm.disable_token_counter is True:\n        return 0\n\n    verbose_logger.debug(\"messages in token_counter: %s, text in token_counter: %s\", messages, text)\n    if text is not None and messages is not None:\n        raise ValueError(\"text and messages cannot both be set\")\n    if use_default_image_token_count is None:\n        use_default_image_token_count = False\n\n    if text is not None:\n        if tools or tool_choice:\n            raise ValueError(\"tools or tool_choice cannot be set if using text\")\n        if isinstance(text, list):\n            text_to_count = \"\".join(t for t in text if isinstance(t, str))\n        elif isinstance(text, str):\n            text_to_count = text\n        count_function: Final = _get_count_function(model, custom_tokenizer)\n        num_tokens = count_function(text_to_count)\n\n    elif messages is not None:\n        new_messages: Final = cast(list[AllMessageValues], convert_list_message_to_dict(messages))\n        params: Final = _MessageCountParams(model, custom_tokenizer)\n        num_tokens = _count_messages(params, new_messages, use_default_image_token_count, default_token_count)\n        if count_response_tokens is False:\n            includes_system_message: Final = any([message.get(\"role\", None) == \"system\" for message in new_messages])\n            num_tokens += _count_extra(params.count_function, tools, tool_choice, includes_system_message)\n\n    else:\n        raise ValueError(\"Either text or messages must be provided\")\n","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/token_counter.py#L363-L399","documentation":"Token counting for tools/tool_choice is only implemented on the messages= path, which mirrors OpenAI's function-definition overhead accounting. When counting a bare text= string there is no place for tool definitions to contribute, so passing tools or tool_choice together with text= is rejected.","triggerScenarios":"litellm.token_counter(text=\"...\", tools=[...]) or token_counter(text=\"...\", tool_choice=\"auto\") - the caller wants a prompt-plus-tools estimate but passed the prompt as text= instead of as messages.","commonSituations":"Cost estimators built around a prompt template string plus a tool list; migrating from counting only the user string to accounting for tool definitions.","solutions":["Wrap the string as messages: token_counter(model=m, messages=[{\"role\": \"user\", \"content\": text}], tools=tools, tool_choice=tc).","If only the raw string count is needed, drop tools/tool_choice from the call."],"exampleFix":"# before\nn = litellm.token_counter(model=\"gpt-4o\", text=prompt, tools=my_tools, tool_choice=\"auto\")\n\n# after\nn = litellm.token_counter(model=\"gpt-4o\",\n    messages=[{\"role\": \"user\", \"content\": prompt}], tools=my_tools, tool_choice=\"auto\")","handlingStrategy":"validation","validationCode":"if tools or tool_choice:\n    assert messages is not None, \"tools counting requires messages=, not text=\"\n    n = litellm.token_counter(model=m, messages=messages, tools=tools, tool_choice=tool_choice)\nelse:\n    n = litellm.token_counter(model=m, text=text, messages=messages)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat tools/tool_choice as companions to messages only.","Centralize token estimation in one helper that enforces the pairing rules."],"tags":["token-counter","validation","tools","api-misuse"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}