I’m getting a TypeError. How do I fix it?

What is a TypeError?

It means exactly what it sounds like: there is an Error that is caused by the Type of one or more of the values in the code.

… but what is a “type”?

In a Python program, every object has a type. By “object” (equivalently in Python, “value”) we mean something that can be given a name in the source code. Most names are simple variables: if we write x = 1, then 1 is an object, it has a name x, and its type is int – the type itself has a name.

“Type” means more or less what it sounds like: it tells you what kind of thing something else is. 1, 2 and 3 are all integers; they have the same type, int. You can think of it as representing the concept of an integer.

Not every type has a built-in name. For example, functions are objects (most other languages don’t work this way!), and they have a type, but we can’t directly refer to that type by name in our code.

Every type does have a representation as an object, however, whether it’s named or not. You can use the built-in type to get such a “type object”:

>>> type(1) # the result from this...
<class 'int'>
>>> int # is the same:
<class 'int'>
>>> type(int) # We can look a bit deeper:
<class 'type'>
>>> def func():
...     pass
>>> type(func) # and get types that aren't named:
<class 'function'>
>>> type(type) # and there's this special case:
<class 'type'>

Notably, the type of type is type itself.

You may notice that Python (3.x) displays these type objects with the word class. This is a useful reminder: when you create a class, you are defining a new type of data. That is the purpose of classes.

What do messages like this mean?

We can break the examples down into a few categories:

TypeError: func() takes 0 positional arguments but 1 was given
TypeError: func() takes from 1 to 2 positional arguments but 3 were given
TypeError: func() got an unexpected keyword argument 'arg'
TypeError: func() missing 1 required positional argument: 'arg'
TypeError: func() missing 1 required keyword-only argument: 'arg'
TypeError: func() got multiple values for argument 'arg'
TypeError: MyClass() takes no arguments

These exceptions are telling you that the arguments (the things you put between the ()) for calling func (or creating an instance of MyClass) are wrong. Either there are too many, not enough, or they are not properly labelled.

This is admittedly a little confusing. We’re trying to call a function, and the thing we’re calling is a function – so the type does actually match. The identified problem is with the number of arguments. However, Python reports this as a TypeError rather than a ValueError. This might be in order to look more familiar to programmers from other languages such as C++, where “types” are checked at compile time and can be very complex – such that functions that accept different types or numbers of arguments, are themselves considered to have different types.

TypeError: unsupported operand type(s) for +: 'int' and 'str'
TypeError: can only concatenate str (not "int") to str
TypeError: '>' not supported between instances of 'int' and 'str'
TypeError: can't multiply sequence by non-int of type 'float'
TypeError: string indices must be integers

These exceptions are telling you that the left-hand side and right-hand side of an operator (a symbol like + or > or ^, used to compute a result) don’t make sense. For example, trying to divide or subtract strings, or repeat a string a non-integer number of times. As a special case, you can use + between two strings (or lists, or tuples), but it doesn’t “add” them in a mathematical sense. If you try to use + between an integer and a string, the error message will be different depending on the order.

TypeError: %d format: a number is required, not str
TypeError: not all arguments converted during string formatting

These ones are a bit tricky. The % operator is used to get the modulus (remainder when dividing numbers), but it can also be used to format strings by replacing some placeholders. (This is an outdated system that’s hard to get right and has weird special cases; in new code, please use f-strings or the .format method.)

An error occurs because the placeholders in the string on the left-hand side don’t match up with what’s on the right-hand side. In the second case, it’s likely that you actually wanted to calculate a modulus, so the left-hand side should be a number (most likely an integer) instead. It’s debatable whether these should be ValueErrors instead, since it could be that the contents of the string are wrong. However, Python cannot read your mind.

TypeError: list indices must be integers or slices, not str

This is also a problem with an operator, this time the [] operator (used for indexing into a list, slicing a list, or looking up a key in a dictionary). A string makes sense inside the [] if we are looking up a key in a dictionary that has strings as keys; but we cannot index into a list with it.

TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'
TypeError: a bytes-like object is required, not 'str'
TypeError: bad operand type for abs(): 'str'

These mean that something wrong was passed to a built-in function (or another callable, such as a type). Functions that you get from a library may raise their own TypeErrors with custom messages. The message should be pretty straightforward.

TypeError: descriptor 'to_bytes' for 'int' objects doesn't apply to a 'str' object

This one is very unusual, and most people who ask this question would never run into it (except maybe with the datetime standard library module). It happens because of trying to use a method as if it were a function, but giving it the wrong type of thing for self: for example, int.to_bytes('1'). The code is wrong because '1' is a string, and strings don’t support .to_bytes. Python will not convert the string to integer; and it cannot give an AttributeError instead because to_bytes was looked up in the class, not on the string.

TypeError: 'int' object is not iterable
TypeError: cannot unpack non-iterable int object
TypeError: 'int' object is not callable
TypeError: 'int' object is not subscriptable

These mean exactly what they sound like. “iterable” means “able to be iterated”; i.e., checked repeatedly to get separate values. This happens in for loops, comprehensions and when trying to convert to list etc. The “unpack” variation of the message results from trying to use unpacking syntax on the non-iterable.

“callable” means “able to be called”; to “call” something is to write () after it (possibly with arguments between the ()). Code like 1('test') doesn’t make sense because 1 isn’t a function (or a type).

“subscriptable” means “able to be subscripted”; here, “subscripting” means either using slice syntax (x[1:2:3]), or indexing or looking for a key (x['test']). We can only do this with sequences (like lists or strings) and mappings (like dicts).

Leave a Comment