How to Fix TypeError: can only concatenate str (not “int”) to str in Python

3D illustration banner explaining string and integer concatenation errors in Python.

In Python, the + and += operators have two completely different jobs: they concatenate strings ("a" + "b" becomes "ab") and they add numbers (10 + 5 becomes 15). Unlike JavaScript or Java, Python is strongly typed and refuses to guess which one you meant. When the value on the left side of + (or +=) is a str and the value on the right side is an int, Python immediately halts with TypeError: can only concatenate str (not "int") to str.

This error happens in two opposite situations: either you tried to build a text message like "Order #" + 1042 without converting the number to a string, or you tried to do math like user_age + 1 (or total += 10) without realizing that the left-hand variable is actually a string ("25" or "0").

Reading the can only concatenate str Traceback

Read the traceback from the bottom up. Because this exact error is raised by str.__add__(), it always means the expression on the left side of + or += evaluated to a str, and the expression on the right side evaluated to the type named inside the double quotes ("int", "numpy.int64", "UUID", "bool", or "NoneType"):

Traceback (most recent call last):
  File "/var/www/app/main.py", line 2, in <module>
    print("Order #" + order_id)
TypeError: can only concatenate str (not "int") to str
  • Python 3.11+ Carets: Starting in Python 3.11+ (not run by me; noted from documentation), the traceback draws ~~~~~~~~~~^~~~~~~~~~ carets under the binary + expression, pointing directly to the + operator that failed.

Tested Environment: Python 3.10.16, NumPy 1.26.3 & Pandas 2.0.0 (Linux) | Python 3.11+ carets, Pandas 3.0+, Polars, and linter/type-checker behaviors not run by me; noted from documentation.

Part of: The Ultimate Python Debugging Guide

⚡ The Quick Fix: Choose Text Formatting or Numeric Addition

Fix the error based on whether you intended to build a string or calculate a number:

1. When You Wanted Text (“Order #1042”): Use an f-String or str()

Modern Python f-strings (f"...", introduced in Python 3.6) automatically format integers, floats, dates, UUIDs, and booleans into strings without clumsy + str(...) chains:

order_id = 1042

# Fails: "Order #" is a str, order_id is an int
# print("Order #" + order_id)

# Best Fix: Use an f-string
print(f"Order #{order_id}")       # Prints: Order #1042

# Alternative 1: Explicitly convert with str()
print("Order #" + str(order_id))  # Prints: Order #1042

# Alternative 2: Pass comma-separated arguments to print()
print("Order #", order_id)        # Prints: Order # 1042

2. When You Wanted Math (“25” + 1 to 26): Convert the String to int()

If the left-hand variable is a numeric string (from input(), os.getenv(), or a file), convert it with int() before adding. (⚠️ Trap: Never “fix” a math line by wrapping the right-hand number in str(1)—writing "25" + str(1) concatenates the strings into "251" instead of calculating 26!)

raw_age = "25"  # e.g., returned from input("Enter age: ")

# Optional input: Fall back to a sensible default if blank or invalid
def add_years_optional(val, years=1, default=0):
    try:
        return int(val) + years
    except (ValueError, TypeError):
        return default

# Required input: Validate and raise a meaningful error if invalid
def add_years_strict(val, years=1):
    try:
        return int(val) + years
    except (ValueError, TypeError) as err:
        raise ValueError(f"Expected integer age, got {val!r}") from err

print(add_years_strict(raw_age, 1))  # Prints: 26

⏱️ The 10-Second Diagnostic: What Your TypeError: can only concatenate str (not “int”) to str Looks Like

Find the pattern that matches your crashing line to grab the exact fix in under 15 seconds:

What the Code Looks LikeRoot CauseThe Exact Fix
“Order #” + 1042Building text with +.Use an f-string: f”Order #{1042}”
user_age + 1 (where user_age = “25”)input() and APIs return strings.Convert to number: int(user_age) + 1
total += price (where total = “0”)Accumulator initialized as str instead of int.Initialize as integer: total = 0
“Total: %d” % 10 + 5% has higher precedence than +.Use an f-string: f”Total: {10 + 5}”
“Price: $” + 19.99+ cannot combine str and float.Format it: f”Price: ${19.99:.2f}”
“Hi ” + user.get(“name”)dict.get() returned None.Coalesce: “Hi ” + (name or “Guest”)
df[“prefix”] + df[“id”]Pandas column is int64, not str.Cast column: df[“id”].astype(str)

Can You Fix This TypeError?

order_id = 1042
message = "Order #" + order_id
print(message)

Choose the best fix:

Inspect Which Side of + Is a String and Which Is an Integer

When you have a line like result = a + b + c where all three variables look like numbers when printed, drop these two lines right above the crash to inspect type() and repr() (which wraps strings in single quotes '25' so they stand out immediately from integers 10):

left = "25"
right = 10

print(f"left:  type={type(left).__name__:<6} | value={left!r}")
print(f"right: type={type(right).__name__:<6} | value={right!r}")

Verified Output (Python 3.10.16):

left:  type=str    | value='25'
right: type=int    | value=10

Common Causes of TypeError: can only concatenate str (not "int") to str

Here are the nine most frequent ways str + int (and its sibling type mismatches) sneak into Python code.

1. Building Strings with + Instead of f-Strings (JavaScript / Java Habit)

In JavaScript ("Score: " + 10) and Java, the + operator automatically coerces numbers into strings whenever one side is a string. Python intentionally forbids implicit string coercion so that accidental string variables don’t silently turn math like "10" + 5 into "105".

  • The Trigger (Verified 3.10.16):
score = 100
msg = "Your score is " + score + " points."
# TypeError: can only concatenate str (not "int") to str
  • The Fix: Replace + concatenation with an f-string:
score = 100
msg = f"Your score is {score} points."
print(msg)  # Your score is 100 points.
  • How to tell it’s this one: The left side of + is a literal string in quotes ("Order #", "Score: ", ",").

2. Doing Math on input(), os.getenv(), or JSON Strings

Built-in input(), environment variable lookups (os.getenv()), command-line arguments (sys.argv), CSV readers (csv.reader), and unvalidated JSON fields always return strings, even if the value looks like digits. When that string variable sits on the left side of + (user_age + 1), Python sees str + int and raises can only concatenate str (not "int") to str—even though you were trying to do addition, not string concatenation!

  • The Trigger (Verified 3.10.16):
user_age = "25"  # Returned by input("Enter your age: ")
next_year = user_age + 1
# TypeError: can only concatenate str (not "int") to str
  • The Fix: Wrap input(), os.getenv(), or the JSON field in int() (or float()) when reading the value:
user_age = int("25")
next_year = user_age + 1
print(next_year)  # Prints: 26
  • How to tell it’s this one: Both variables represent numbers in your business logic, and the left variable came from input(), os.getenv(), sys.argv, a CSV row, or an API payload.

3. The += Operator Traps (String Building & String Accumulators)

Augmented assignment (+=) on a string triggers this error in two common ways:

  1. Appending an Integer to a Log/Message String (msg += 10): Unlike list.__iadd__ (where my_list += "42" works because strings are iterable), str has no special += coercion and raises TypeError: can only concatenate str (not "int") to str.
  2. The String Accumulator Trap (total = "0"): If you accidentally initialize a counter or running total as the string "0" (or seed it from an uncast CSV/JSON string total = row["start_balance"]) instead of the integer 0, the very first total += price inside your loop crashes! (⚠️ Trap: Never fix total += price by writing total += str(price)—for [10, 20, 30], that concatenates digits onto "0" and produces the string "0102030" instead of 60!)
  • The Trigger (Verified 3.10.16):
# Trap A: Appending an int to a string with +=
msg = "Score: "
msg += 10  # TypeError: can only concatenate str (not "int") to str

# Trap B: Initializing a numeric accumulator as a string "0"
total = "0"
for price in [10, 20, 30]:
    total += price  # TypeError: can only concatenate str (not "int") to str
  • The Fix: Use msg += str(10) when appending text, and initialize numeric accumulators as int or float (total = 0):
msg = "Score: "
msg += str(10)

total = 0
for price in [10, 20, 30]:
    total += price
print(msg, "| Total:", total)  # Score: 10 | Total: 60
  • How to tell it’s this one: The traceback points to a line with +=.

4. Concatenating len(), range(), and enumerate() Loop Counters

Built-in len() always returns an int, and loop helpers like range() and enumerate() yield int indices. Concatenating them directly into status messages or dictionary keys with + fails on the first iteration.

  • The Trigger (Verified 3.10.16):
items = ["apple", "banana"]
# Fails: len(items) returns int 2
print("Total items: " + len(items))

# Fails: 'idx' from enumerate() or range() is an int
for idx, item in enumerate(items):
    print("Row " + idx + ": " + item)
  • The Fix: Format len(items) and loop counters inside an f-string:
items = ["apple", "banana"]
print(f"Total items: {len(items)}")

for idx, item in enumerate(items, start=1):
    print(f"Row {idx}: {item}")
  • How to tell it’s this one: The right side of + is len(...) or a loop index variable (i, idx, count) from range() or enumerate().

5. Operator Precedence Traps with % String Formatting ("%d" % 10 + 5)

In legacy Python % string formatting, the % operator has the exact same precedence as multiplication * and division /, which is higher than +. If you write "Total: %d" % 10 + 5 intending to format 10 + 5, Python actually evaluates ("Total: %d" % 10) + 5 first—turning the left side into "Total: 10" and crashing when it tries to add + 5!

  • The Trigger (Verified 3.10.16):
# Python evaluates ("Total: %d" % 10) first -> "Total: 10" + 5
msg = "Total: %d" % 10 + 5
# TypeError: can only concatenate str (not "int") to str
  • The Fix: Switch to an f-string (f"Total: {10 + 5}"), or wrap the math expression in parentheses ("Total: %d" % (10 + 5)):
msg = f"Total: {10 + 5}"
print(msg)  # Prints: Total: 15

How to tell it’s this one: The failing line combines % string formatting and + without parentheses around the math.

Can You Fix This TypeError?

user_age = "25"
next_year = user_age + 1
print(next_year)

Choose the best fix:

6. NumPy Scalars (not "numpy.int64") from Array or DataFrame Indexing

When you extract a single integer from a NumPy array (arr[0]) or a Pandas Series (df["id"].iloc[0]), you get a NumPy scalar object (numpy.int64) rather than a standard Python int.

  • When np.int64 is on the right ("Val: " + np.int64(42)): Python raises TypeError: can only concatenate str (not "numpy.int64") to str.
  • When np.int64 is on the left (np.int64(42) + "Val"): NumPy’s universal function (ufunc) dispatcher intercepts the + operator and raises UFuncTypeError: ufunc 'add' did not contain a loop with signature matching types (dtype('int64'), dtype('<U3')) -> None.
  • The Trigger (Verified NumPy 1.26.3):
import numpy as np

ids = np.array([101, 102])
print("User_" + ids[0])
# TypeError: can only concatenate str (not "numpy.int64") to str
  • The Fix: Use an f-string (f"User_{ids[0]}"), convert with str(ids[0]), or extract a native Python integer with ids[0].item().

7. Concatenating datetime, UUID, and bool Objects to a String

In web frameworks (Django, FastAPI, Flask) and database scripts, developers frequently concatenate timestamps, UUID primary keys, or boolean flags directly into URLs, cache keys, or log strings:

  • datetime.date or datetime.datetime ("Date: " + d): Raises TypeError: can only concatenate str (not "datetime.date") to str. Fix with f"Date: {d:%Y-%m-%d}" or "Date: " + d.isoformat().
  • uuid.UUID ("/users/" + user_id): Raises TypeError: can only concatenate str (not "UUID") to str. Even though UUIDs look like hyphenated strings when printed, uuid.uuid4() returns a UUID object. Fix with f"/users/{user_id}" or str(user_id).
  • bool ("Active: " + True): Raises TypeError: can only concatenate str (not "bool") to str. Even though bool is a subclass of int in Python (so True + 1 evaluates to 2!), str.__add__ rejects booleans just like integers. Fix with f"Active: {flag}".
  • The Trigger (Verified 3.10.16):
import datetime, uuid

today = datetime.date(2026, 10, 31)
user_uuid = uuid.UUID("12345678-1234-5678-1234-567812345678")
is_active = True

# Each line below raises TypeError: can only concatenate str (not "...") to str:
# print("Date: " + today)        # not "datetime.date"
# print("ID: " + user_uuid)      # not "UUID"
# print("Active: " + is_active)  # not "bool"
  • The Fix: Combine all three cleanly inside an f-string:
print(f"Date: {today.isoformat()} | ID: {user_uuid} | Active: {is_active}")

8. Concatenating float, NoneType, list, or bytes to a String

Python raises the same can only concatenate str (not "...") to str message for other core types:

  • not "float" ("$" + 19.99): Format the float with an f-string (f"${price:.2f}") to control decimal places cleanly.
  • not "NoneType" ("User: " + user.get("name")): A dictionary lookup, os.getenv(), or regex search returned None (see our NoneType AttributeError Guide). Coalesce optional values with "User: " + (user.get("name") or "Guest"), or validate required values first.
  • not "list" ("Tags: " + ["python", "seo"]): Convert the list into a string with ", ".join(tags) before concatenating: "Tags: " + ", ".join(tags).
  • not "bytes" ("Hello " + b"world" vs. b"Hello " + "world"): Putting str on the left ("Hello " + b"world") raises TypeError: can only concatenate str (not "bytes") to str, while putting bytes on the left (b"Hello " + "world") raises TypeError: can't concat str to bytes. Decode the bytes object first (raw_bytes.decode("utf-8")) if you want a str, or encode the str (text.encode("utf-8")) if you want bytes.

9. Concatenating String and Integer Columns in Pandas (df["code"] + df["id"]) and Polars

In Pandas 2.0.0, combining a string (object or string) column and an integer (int64) column with + raises a long traceback ending in TypeError: can only concatenate str (not "int") to str.

  • The Trigger (Verified Pandas 2.0.0):
import pandas as pd

df = pd.DataFrame({"code": ["ORD", "ORD"], "id": [101, 102]})
# Fails: 'code' is object (str), 'id' is int64
df["label"] = df["code"] + "-" + df["id"]
# TypeError: can only concatenate str (not "int") to str
  • The Fix (Pandas & Polars):
  • In Pandas: Convert the integer column to strings first with .astype(str):
import pandas as pd

df = pd.DataFrame({"code": ["ORD", "ORD"], "id": [101, 102]})
df["label"] = df["code"] + "-" + df["id"].astype(str)
print(df["label"].tolist())  # ['ORD-101', 'ORD-102']
  • ⚠️ Missing Values Note (Pandas 2.x vs. 3.0+): When a numeric column contains None or NaN, Pandas defaults the column to float64. In Pandas 2.0.0 (verified), .astype(str) converts missing values into literal text (['101.0', 'nan'], or ['101', '<NA>'] via "Int64"). In Pandas 3.0+ (not run by me; noted from documentation), .astype(str) uses the nullable string dtype so missing values stay missing (['101.0', nan] on float64, and ['101', nan] via "Int64"). To avoid .0 suffixes across all versions, cast to "Int64" first (df["id"].astype("Int64").astype(str)).
  • In Polars (not run by me; noted from documentation): Use pl.format("{}-{}", pl.col("code"), pl.col("id")) or cast the integer column with pl.col("id").cast(pl.String) before concatenating.

Why "10" + 5 and 5 + "10" Raise Different TypeError Messages

A frequent point of confusion is why swapping the two sides of + changes the error message entirely:

ExpressionVerified Error Message (Python 3.10.16)Why Python Raises This Specific Message
"10" + 5 (str on left, int on right)TypeError: can only concatenate str (not "int") to strPython calls the left object’s "10".__add__(5) method. Because str.__add__ only accepts str instances, it immediately raises this string-specific TypeError.
5 + "10" (int on left, str on right)TypeError: unsupported operand type(s) for +: 'int' and 'str'Python calls the left object’s (5).__add__("10") method, which returns NotImplemented. Python then checks "10".__radd__(5) (which does not exist) and raises the generic binary operator TypeError.
np.int64(10) + "5" (NumPy int64 on left)UFuncTypeError: ufunc 'add' did not contain a loop with signature matching types...NumPy’s array add ufunc intercepts + and fails because no numeric addition loop exists between int64 and Unicode strings.

In all three cases, the fix is identical: use f"{a}{b}" if you want a string, or int(a) + int(b) if you want arithmetic addition.

Sibling String & Operator TypeError Variants

Here are the closely related TypeError variants you will hit when mixing strings, bytes, and numbers across other Python operations (all verified on Python 3.10.16):

Error Message Variant (Verified 3.10.16)What Triggered ItThe Fix
TypeError: unsupported operand type(s) for +: 'int' and 'str'Adding int + str (10 + "5"), or calling sum(["a", "b"]) (because sum() starts at integer 0 and computes 0 + "a").Convert "5" with int("5") for math, or use "".join(["a", "b"]) instead of sum() to join strings.
TypeError: unsupported operand type(s) for -: 'str' and 'int'Subtracting an integer from a string ("10" - 5), or using / or // with a string.Convert the string to a number first: int("10") - 5.
TypeError: can't concat str to bytesAdding bytes + str (b"a" + "b"), the reverse of "a" + b"b".Decode the bytes (b"a".decode("utf-8") + "b") or encode the string (b"a" + "b".encode("utf-8")).
TypeError: sequence item 0: expected str instance, int foundPassing a list containing integers to str.join(), such as ", ".join([1, 2, 3]).Convert each item to a string inside a generator expression: ", ".join(str(x) for x in [1, 2, 3]).
TypeError: can't multiply sequence by non-int of type 'str'Multiplying two strings ("10" * "5") or multiplying a list by a string (["a"] * "5").Convert the multiplier to an int ("10" * int("5")), or convert both sides to int for math (int("10") * int("5")).
TypeError: can only concatenate list (not "int") to listTrying to append an integer to a list using + ([1, 2] + 3 instead of [1, 2] + [3]).Use my_list.append(3) (in place) or wrap the item in brackets: [1, 2] + [3].

Catch str + int Bugs Before Runtime with Type Checkers and Linters

Static analysis tools flag mismatched + operands and legacy % formatting traps in your editor before you run the script (linter and type checker behaviors noted from documentation):

  1. Pyright / Pylance (reportOperatorIssue) & Mypy (operator): Both Mypy (under the operator error code) and Pyright / Pylance (under reportOperatorIssue) immediately underline "Order #" + order_id or user_age + 1 in red when one side is typed as str and the other as int.
  2. Ruff (UP031, UP032) & Pylint (C0209 consider-using-f-string): These rules flag legacy % formatting and .format() calls and convert them to f-strings, which directly prevents the "%d" % 10 + 5 operator precedence trap covered in Cause #5.

Worked Example: Fixing a String Price in an API Checkout Calculation

Let’s walk through a realistic bug where an e-commerce checkout function crashes because an external JSON payload returned "price" as a string "49" instead of an integer 49.

The Code (/var/www/app/main.py):

def calculate_total(item_payload, shipping_fee):
    return item_payload["price"] + shipping_fee

payload = {"item": "Keyboard", "price": "49"}
print(calculate_total(payload, 10))

Verified Traceback (Python 3.10.16):

Traceback (most recent call last):
  File "/var/www/app/main.py", line 5, in <module>
    print(calculate_total(payload, 10))
  File "/var/www/app/main.py", line 2, in calculate_total
    return item_payload["price"] + shipping_fee
TypeError: can only concatenate str (not "int") to str

The Thought Process & Fix:

  1. Line 2 attempts item_payload["price"] + shipping_fee.
  2. Because item_payload["price"] is the string "49" (on the left of +) and shipping_fee is the integer 10 (on the right of +), Python calls "49".__add__(10) and raises TypeError: can only concatenate str (not "int") to str.
  3. The Result: Convert "price" to a number before adding shipping_fee. 💡 Production Note on Decimal Prices: Real API payloads frequently store prices with cents like "49.99", which makes int("49.99") raise ValueError: invalid literal for int() with base 10. For whole-number quantities, use int(); for currency and financial totals, use Decimal from Python’s built-in decimal module to avoid floating-point rounding errors:
from decimal import Decimal, InvalidOperation

# Approach A (Optional whole-number field): Default to 0 if missing or invalid
def calculate_total_optional(item_payload, shipping_fee, default_price=0):
    try:
        price = int(item_payload.get("price", default_price))
    except (ValueError, TypeError):
        price = default_price
    return price + shipping_fee

# Approach B (Required / Production Money): Validate with Decimal
def calculate_total_strict(item_payload, shipping_fee):
    try:
        price = Decimal(str(item_payload["price"]))
    except (KeyError, InvalidOperation, TypeError) as err:
        raise ValueError(f"Invalid or missing 'price' in payload: {item_payload!r}") from err
    return price + Decimal(str(shipping_fee))

payload = {"item": "Keyboard", "price": "49.99"}
print("Total:", calculate_total_strict(payload, "10.00"))
# Verified Output: Total: 59.99

Can You Fix This TypeError?

df = pd.DataFrame({"code": ["ORD"], "id": [101]})
df["label"] = df["code"] + "-" + df["id"]
print(df["label"])

Choose the best fix:

Frequently Asked Questions

Why does "10" * 3 work in Python ("101010"), while "10" + 3 raises a TypeError?

In Python, multiplying a sequence (like a str, list, or tuple) by an integer n is explicitly defined as sequence repetition—repeating the string n times ("10" * 3 produces "101010"). By contrast, + on a string is defined strictly as string concatenation, which requires both sides to be strings so Python never confuses "10" + 3 ("103" vs. 13).

What is the fastest and cleanest way to combine strings and numbers in Python?

Use an f-string (f"Order #{order_id}: ${total:.2f}"). Not only are f-strings more readable than "Order #" + str(order_id), they are compiled directly into dedicated string-building bytecode in CPython and are usually faster than both + str() and .format().

Why did sum(["a", "b", "c"]) raise TypeError: unsupported operand type(s) for +: 'int' and 'str'?

Built-in sum(iterable, start=0) defaults its starting value to the integer 0. On the very first step, Python attempts 0 + "a", which fails because you cannot add an int and a str (and Python explicitly blocks sum(strings, "") for performance reasons). Always use "".join(["a", "b", "c"]) to concatenate a list of strings.

How do I concatenate a list of integers [1, 2, 3] into a comma-separated string "1, 2, 3"?

Pass a generator expression that converts each integer to a str inside .join(): ", ".join(str(x) for x in [1, 2, 3]). Calling ", ".join([1, 2, 3]) directly without str(x) raises TypeError: sequence item 0: expected str instance, int found.

Similar Posts

Leave a Reply