PythonMastery
reference 3 min read · lesson 49 of 60 in Errors

TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

1 · The lesson

read

What this error means

You tried to add a number to None. Python has no rule for None + 5, so it stops. The message tells you which side was None: 'NoneType' and 'int' means the left side, 'int' and 'NoneType' means the right.

The + is rarely where the bug lives. Somewhere earlier, a value you expected to be a number turned out to be None, and the + is just the first line that cared.

When you see it

python
Traceback (most recent call last):
  File "main.py", line 7, in <module>
    grand_total = subtotal(basket) + 5
                  ~~~~~~~~~~~~~~~~~^~~
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
python
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    total += stock.get(item)
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'

Same bug, different operator. You'll also see -, * and / versions.

Why it happens

None is what you get when nothing was returned. The usual sources:

1. The function forgot to return. A function that falls off the end returns None, even if it computed the right answer along the way.
2. It prints instead of returning. The number appears on screen, which looks like success, but the caller gets None.
3. A method that changes things in place. list.sort(), list.append(), random.shuffle() and dict.update() all return None. Assigning their result throws the list away.
4. dict.get() with no default. A missing key gives None, not 0.

python
def subtotal(basket):
    total = sum(item["price"] for item in basket)
    print(f"Subtotal: {total}")      # shows the right number...

basket = [{"price": 12.5}, {"price": 7.5}]
grand_total = subtotal(basket) + 5   # ...but returns None

How to fix it

Return the value. Keep the print if you like, but the function has to hand the number back:

python
def subtotal(basket):
    total = sum(item["price"] for item in basket)
    return total

basket = [{"price": 12.5}, {"price": 7.5}]
grand_total = subtotal(basket) + 5   # delivery
print(grand_total)                   # 25.0

If a function has several branches, check that every one of them returns. A single if with no else is enough to leak a None out of the other path.

Don't assign the result of an in-place method. Call it, then use the original — or use the version that returns a new object:

python
scores = [72, 91, 64]

scores.sort()                  # sorts scores; returns None
print(scores + [100])          # [64, 72, 91, 100]

ranked = sorted(scores, reverse=True)   # sorted() returns a new list
print(ranked)                  # [91, 72, 64]

Give dict.get() a default that makes sense for the arithmetic:

python
stock = {"earl grey": 14, "oat milk": 6}
order = ["earl grey", "oat milk", "matcha"]

total = 0
for item in order:
    total += stock.get(item, 0)       # matcha isn't stocked: counts as 0
print(total)                          # 20

Only use 0 when zero is genuinely the right answer. If a missing price means the data is broken, let it fail — but fail with a message that names the item, not a NoneType error three lines later.

Skip missing values deliberately when they come from data, such as blank cells in a CSV:

python
amounts = [19.99, None, 45.00, None, 8.50]
print(sum(a for a in amounts if a is not None))   # 73.49

When you'd actually see this in real code

  • A helper that started life as a debugging script, full of print() calls, and later got called from other code.
  • sum(row["amount"] for row in rows) where one row parsed from JSON had "amount": null. That one surfaces as 'int' and 'NoneType', because sum starts from 0.
  • A recursive function where the base case returns a number but the recursive branch forgets return in front of the call.
  • config.get("retries") + 1 when the setting was never written to the file.

See Also

Found this useful? Share it with a friend who’s learning Python.