TypeError in Python: where it comes from and how to fix it

TypeError reports an operation applied to a type that does not support it, such as adding a number to a string.
5 min read
Believemy logo

Definition

Writing Python gives the impression of great freedom: no variable carries a declared type, and nothing forces you to think about types before running the program. That freedom meets its limit the moment two values of different natures meet inside the same operation, an addition, a comparison, a concatenation. Python then has to choose between guessing what you meant and stopping outright. It stops, and that refusal is exactly what TypeError reports: an operation applied to a type that does not support it.

That choice is not a lack of flexibility, it is a deliberate stance. Python is dynamically typed, it does not ask you to declare types up front, but it stays strongly typed: it never mixes them on its own, unlike other languages that would have decided for you.

PYTHON
age = "25"
age + 1

# TypeError: can only concatenate str (not "int") to str

Concatenating would have produced "251", converting would have produced 26. Neither answer is more correct than the other, which is precisely the sign that no automatic conversion would make sense here. An explicit error at the line where the problem occurs beats a silently wrong result discovered three weeks later.


The causes, by frequency

The table below ranks them by how often they show up, with the reflex that fixes each one.

SituationWhat to do
An input or a read field is still textConvert with int or float
A function handed back NoneCheck it really holds a return
Wrong number of argumentsCompare the call with the signature
An object is not callableBrackets placed on something other than a function
An unorderable type is sortedSupply an explicit sort key
Good to know

A particular case of "not callable" comes up often: naming a variable after a built in type, for instance list = [1, 2, 3], then calling list(range(3)) further down. Python does not complain at the assignment, only at the next call, once list no longer refers to the type but to your variable.

The "NoneType object is not subscriptable" message is worth recognising at a glance: it means None is being indexed as if it were a list or a dictionary. The natural instinct is to fix the line Python points to, and that is almost always the wrong lead.

Warning

The line Python reports shows where the error breaks out, not where it was born. For NoneType is not subscriptable, the real cause is almost always a function further up, the one that handed back None instead of the expected value.


The message says everything

Once you know where to look, the next question is what to fix. Unlike many Python errors that just name the problem, TypeError goes further: it names both types involved. "unsupported operand type(s) for +: 'int' and 'str'" gives the operation, the left type and the right one. All that is left is spotting which of the two should not be there.

The fix then almost always follows the same path: convert the suspect value before it meets the operation that fails, rather than at the moment of the calculation itself.

PYTHON
# The usual fix: convert on reading
quantity = int(row["quantity"])
total = price * quantity

Converting at the entry point, rather than at computation time, changes something concrete: validation happens once, in one place, instead of being copied everywhere the data travels afterward.


The argument case

Not every TypeError comes from a mismatched calculation. A good half concern not a value but a function call. The message there is even more precise: it gives the function name, the number of arguments expected, and often the one missing by name.

PYTHON
def send(recipient, subject, body):
    ...

send("a@b.com", "Hello")

# TypeError: send() missing 1 required positional argument: 'body'

On a method, this same kind of message hides a classic trap. self counts as an argument, even though no one ever writes it at the call site: it is what the method receives first. A message announcing two arguments expected for one supplied almost never points to something you forgot, but to a call made on the class itself rather than on an instance, which leaves Python without the self it expected.


Frequently asked questions

Question

How does it differ from ValueError?

The distinction comes down to what is actually wrong. TypeError is about the nature of the data, ValueError about its content, with the type staying correct. int("abc") raises a ValueError: a string is an acceptable type for int(), only its content will not convert. int([1, 2]) raises a TypeError instead, because a list simply is not the kind of thing int() knows how to handle.

Question

Do type annotations prevent it?

No, and that is a common confusion for beginners. Python ignores annotations at runtime: they document intent and feed analysis tools. It is that tooling, run before release, that catches the type mismatch upstream, not the interpreter.

Question

Why does adding two numbers fail?

Most often because one of the two is not really a number, even though everything suggests it is. A field read from a file, a response from a remote interface or a user input almost always arrive as text, even when that text holds nothing but digits. Nothing in their appearance gives away their real type: only the error reveals it.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.