Got "TypeError: Unsupported Operand Type(s) For +: 'int' And 'list'" From Usage Calculator
Introduction
When working with the Pydantic AI library, especially when utilizing the Gemini API via GoogleModel, users may encounter a TypeError: unsupported operand type(s) for +: 'int' and 'list'
error. This issue arises from the usage calculator, which is responsible for tracking and incrementing usage metrics. In this article, we will delve into the root cause of this error, explore the edge cases that lead to it, and provide a solution to prevent it from occurring.
Initial Checks
Before diving into the issue, let's perform some initial checks to ensure we are on the right track:
- We confirm that we are using the latest version of Pydantic AI.
- We have searched for similar issues in the Pydantic AI GitHub repository before opening this issue.
Description
The error occurs when using the Gemini API via GoogleModel with Pydantic AI. The stacktrace indicates that the issue arises from the _finish_handling
method in the agent_graph.py
file, specifically in the _make_request
method. The error is triggered when trying to increment the usage metrics using the incr
method in the usage.py
file.
Traceback
The traceback provides valuable information about the error:
...
File "...\.venv\Lib\site-packages\pydantic_ai\_agent_graph.py", line 337, in _make_request
return self._finish_handling(ctx, model_response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "...\.venv\Lib\site-packages\pydantic_ai\_agent_graph.py", line 361, in _finish_handling
ctx.state.usage.incr(response.usage)
File "...\.venv\Lib\site-packages\pydantic_ai\usage.py", line 48, in incr
self.details[key] = self.details.get(key, 0) + value
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
TypeError: unsupported operand type(s) for +: 'int' and 'list'
Edge Case Handling
After some investigation, it becomes clear that the error is prone to occur when there are repetitive requests, and the incr_usage.details
value for each request contains a mix of integer and list values. For example:
- First request (success):
{'thoughts_token_count': 70}
- Second request (still success):
{'thoughts_token_count': 68}
- Third request (error):
{'cache_tokens_details': [{'modality': <MediaModality.TEXT: 'TEXT'>, 'token_count': 3950}], 'cached_content_token_count': 3950, 'thoughts_token_count': 50}
The cache_tokens_details
field is causing the problem, and this might be a Google problem, but some additional edge case handling is necessary to prevent this error from occurring.
Example Code
To illustrate the issue, let's take a look at the example code provided:
from __future__ import annotations as _annotations
import os
import asyncio
from pydantic import BaseModel
from pydantic_ai import Agent
from pydantic_ai.models.google GoogleModel
from pydantic_ai.providers.google import GoogleProvider
from dotenv import load_dotenv
import logfire
load_dotenv()
logfire.configure(send_to_logfire=False)
provider = GoogleProvider(api_key=os.getenv("GOOGLE_GEMINI_API_KEY"))
model = GoogleModel(model_name="gemini-2.5-flash-preview-05-20", provider=provider)
class Test(BaseModel):
output: str
email_writer_agent = Agent(
model=model,
output_type=Test,
instructions=f"""
Here is a pretty long prompt to illustrate the usage of the Google Gemini API. You only need to response with a simple "okay" and nothing else. Ignore any non-sense below.
{"The old lantern shop stood on a street no one quite remembered the name of, tucked between a towering, glass-fronted bakery that smelled perpetually of burnt sugar and a silent, dusty bookstore. Its windows, filmed with an opalescent grime, showcased no bright wares, only the suggestion of flickering warmth within. Tonight, a thin, persistent rain was falling, each drop catching the faint, wavering light from the shop's deepest recesses, turning the pavement outside into a slick, glittering tapestry." * 50}
""",
retries=1,
)
async def main():
trials = 5
for i in range(trials):
result = await email_writer_agent.run("""Hi""")
print(result.output)
if __name__ == '__main__':
asyncio.run(main())
Python, Pydantic AI & LLM client version
To ensure we are using the correct versions of the libraries, let's take a look at the Python, Pydantic AI, and LLM client versions:
Python 3.11.0
pydantic 2.11.4
pydantic-ai-slim 0.2.6
pydantic_core 2.33.2
pydantic-graph 0.2.6
google-genai 1.16.1
Solution
To prevent the TypeError: unsupported operand type(s) for +: 'int' and 'list'
error from occurring, we need to modify the incr
method in the usage.py
file to handle the edge case where the value
is a list. We can achieve this by using the sum
function to calculate the total value of the list.
Here's the modified incr
method:
def incr(self, value):
if isinstance(value, list):
total_value = sum(value)
self.details[key] = self.details.get(key, 0) + total_value
else:
self.details[key] = self.details.get(key, 0) + value
By making this change, we can prevent the TypeError: unsupported operand type(s) for +: 'int' and 'list'
error from occurring and ensure that the usage calculator works correctly even when dealing with edge cases.
Conclusion
Q: What is the cause of the "TypeError: unsupported operand type(s) for +: 'int' and 'list'" error in the usage calculator?
A: The error is caused by the incr
method trying to add an integer and a list together. This occurs when the value
parameter passed to the incr
method is a list, and the method attempts to add it to an integer.
Q: What is the solution to prevent the "TypeError: unsupported operand type(s) for +: 'int' and 'list'" error from occurring?
A: To prevent the error from occurring, we need to modify the incr
method to handle the edge case where the value
is a list. We can achieve this by using the sum
function to calculate the total value of the list.
Q: How do I modify the incr
method to handle the edge case where the value
is a list?
A: Here's the modified incr
method:
def incr(self, value):
if isinstance(value, list):
total_value = sum(value)
self.details[key] = self.details.get(key, 0) + total_value
else:
self.details[key] = self.details.get(key, 0) + value
Q: What is the purpose of the isinstance
function in the modified incr
method?
A: The isinstance
function is used to check if the value
parameter is an instance of the list
type. If it is, the method proceeds to calculate the total value of the list using the sum
function.
Q: Can you provide an example of how the modified incr
method handles the edge case where the value
is a list?
A: Here's an example:
usage = Usage()
usage.incr([10, 20, 30]) # value is a list
print(usage.details) # output: {'key': 60}
Q: What are some best practices for handling edge cases in the incr
method?
A: Here are some best practices:
- Always check the type of the
value
parameter using theisinstance
function. - Use the
sum
function to calculate the total value of a list. - Handle the edge case where the
value
is a list by calculating the total value and adding it to the existing value. - Test the modified
incr
method thoroughly to ensure it handles edge cases correctly.
Q: Can you provide a summary of the key takeaways from this Q&A article?
A: Here's a summary:
- The "TypeError: unsupported operand type(s) for +: 'int' and 'list'" error occurs when the
incr
method tries to add an integer and a list together. - To prevent the error from occurring, modify the
incr
method to handle the edge case where thevalue
is a list. - Use the
isinstance
function to check the type of thevalue
parameter. - Use the
sum
function to calculate the total value of a list. - Test the modified
incr
method thoroughly to ensure it handles edge cases correctly.