From bf81334046126326c0491517ab03addfb598c4cb Mon Sep 17 00:00:00 2001 From: dlowzzxx Date: Fri, 11 Sep 2026 23:02:59 +0200 Subject: [PATCH] fix(token_counter): handle tool array schema without items property (#40344) Prevent KeyError: 'items' when tool parameter schema defines type: array without an items specification by falling back to any[]. --- litellm/litellm_core_utils/token_counter.py | 6 ++-- .../test_token_counter_tool.py | 29 +++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/litellm/litellm_core_utils/token_counter.py b/litellm/litellm_core_utils/token_counter.py index 1de2533d514..f08ec7bc62c 100644 --- a/litellm/litellm_core_utils/token_counter.py +++ b/litellm/litellm_core_utils/token_counter.py @@ -987,8 +987,10 @@ def _format_type(props, indent): return " | ".join([f'"{item}"' for item in props["enum"]]) return "string" elif type == "array": - # items is required, OpenAI throws an error if it's missing - return f"{_format_type(props['items'], indent)}[]" + items = props.get("items") + if isinstance(items, dict): + return f"{_format_type(items, indent)}[]" + return "any[]" elif type == "object": return f"{{\n{_format_object_parameters(props, indent + 2)}\n}}" elif type in ["integer", "number"]: diff --git a/tests/test_litellm/litellm_core_utils/test_token_counter_tool.py b/tests/test_litellm/litellm_core_utils/test_token_counter_tool.py index 9f8c1070a47..045c1a13eb1 100644 --- a/tests/test_litellm/litellm_core_utils/test_token_counter_tool.py +++ b/tests/test_litellm/litellm_core_utils/test_token_counter_tool.py @@ -31,9 +31,7 @@ def test_token_counter_tool_increases(messages): conversation.append(message) tokens = token_counter(model="gpt-3.5-turbo", messages=conversation, tools=TOOLS) # type: ignore print(f"tokens: {tokens}") - assert ( - tokens > prev_tokens - ), f"Token did not increase: {tokens} <= {prev_tokens}" + assert tokens > prev_tokens, f"Token did not increase: {tokens} <= {prev_tokens}" prev_tokens = tokens @@ -76,3 +74,28 @@ def assertGrow(usermessage, tool_call, assertBiggerThanBoth=True): f"tokens_usermessage: {tokens_usermessage}, tokens_tool_call: {tokens_tool_call}, " + f"tokens_both: {tokens_both} diff: {tokens_usermessage + tokens_tool_call - tokens_both}" ) + + +def test_token_counter_tool_array_schema_without_items(): + """Test that tool array schema without 'items' property does not crash token counting (#40344).""" + tools = [ + { + "type": "function", + "function": { + "name": "search_data", + "description": "Search for data", + "parameters": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "description": "List of tags", + }, + }, + }, + }, + } + ] + messages = [{"role": "user", "content": "Hello"}] + tokens = token_counter(model="gpt-3.5-turbo", messages=messages, tools=tools) + assert tokens > 0