DEV Community

Cover image for Python's 'Can Only Concatenate str (Not int) to str'
SystemCraftDev
SystemCraftDev

Posted on Originally published at systemcraftpress.com

Python's 'Can Only Concatenate str (Not int) to str'

Python won't guess whether you meant text or math. The error means you joined a string and a number with +. Here's why it happens and how to fix it.

Adapted from the Python Essentials Companion Guide.


You write a friendly message that includes a number:

age = 30
print("I am " + age + " years old")
Enter fullscreen mode Exit fullscreen mode
TypeError: can only concatenate str (not "int") to str
Enter fullscreen mode Exit fullscreen mode

It looks like it should work. Other languages quietly turn the number into text and carry on. Python stops and tells you it can't, and the wording of the message makes it sound like a rule about "concatenation" you've never heard of. It's simpler than that: you asked Python to join text and a number, and it refuses to guess which one you meant.

What's actually happening

The + operator does two different jobs in Python. Between two numbers it adds them. Between two strings it joins them end to end, which is called concatenation:

2 + 3        # 5
"2" + "3"    # '23'
Enter fullscreen mode Exit fullscreen mode

Same symbol, two meanings, and Python picks the meaning from the types of the values on either side. When one side is a string and the other is an integer, neither meaning applies. Adding makes no sense with text, and joining makes no sense with a number. Some languages settle the question by converting one side automatically. Python deliberately doesn't, because a guess would hide bugs: is "5" + 3 supposed to be 8 or "53"? Python makes you say.

The error message is describing exactly that: "can only concatenate str (not "int") to str" means the + is trying to join onto a string, and the thing you gave it isn't one. If you reverse the order, you get a different-sounding message for the same problem:

>>> 30 + " years"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Enter fullscreen mode Exit fullscreen mode

Same cause, since the types still don't match. The text just changes depending on which side is the string.

The fix, step by step

1. Find the + and work out which side is text and which is a number. The line in the traceback points at it. If you're not sure of a value's type, print it: print(type(age)). If the traceback itself is unfamiliar, How to Read a Python Traceback Without Panicking walks through it.

2. If you're building a message, use an f-string. It's the cleanest fix, because it converts the number for you:

age = 30
print(f"I am {age} years old")      # I am 30 years old
Enter fullscreen mode Exit fullscreen mode

Anything inside the braces is turned into text automatically, and you don't need + at all.

3. If you want to keep +, convert the number with str():

print("I am " + str(age) + " years old")
Enter fullscreen mode Exit fullscreen mode

4. If you actually want math, convert the text to a number instead. This is the common case with input(), which always returns a string, even when the user types digits:

x = input("Number: ")     # user types 7
print(x + x)              # 77, not 14
print(int(x) + int(x))    # 14
Enter fullscreen mode Exit fullscreen mode

Use int() for whole numbers and float() for decimals.

Two mistakes worth knowing about ahead of time

Getting a string result when you expected math. Not every mix-up raises an error. If both values are strings, + happily joins them, and you get the wrong answer without any warning: "5" + "3" is "53", not 8. If a total comes out as a long string of digits, the values are probably still text. This is another reason to convert input as soon as you receive it.

Converting the wrong way and hitting a different error. Once you add int(), bad input gives you a new message. int("abc") raises ValueError: invalid literal for int() with base 10: 'abc', and so does int("5.5"), because int() doesn't accept a decimal point in a string. Use float("5.5") for decimals, or check the input before converting. Leading and trailing spaces are fine: int(" 5 ") works.

A habit that prevents the confusion entirely

Decide what type a value should be at the moment it enters your program, and convert it once, there. Text from input(), a file, or a web form is always a string, so turn it into a number as soon as you read it, and keep it a number from then on. And when you build messages for people to read, reach for an f-string by default. It removes the need to convert, join, and keep track of types in the same expression, which is where this error almost always comes from.


If you'd like more posts like this sent straight to your inbox, subscribe to the newsletter.

Prefer to dig in yourself? The Python Essentials repo on GitHub has more free examples and exercises.

Top comments (0)