String concatenation is one of the most basic operations in Python, but it can trip you up when one of the values you're trying to join turns out to be None instead of a string. The error TypeError: can only concatenate str (not 'NoneType') to str is Python's way of telling you that you're trying to glue a string together with something that isn't a string. In this guide, we'll explore why this happens, look at the most common scenarios that cause it, and walk through multiple ways to fix it.
Understanding the Error
In Python, the + operator can concatenate two strings together, but both operands must be strings. If either side is None (which has the type NoneType), Python doesn't know how to combine them and raises a TypeError.
❌ Example that triggers the error:
name = "Alice"
greeting = "Hello, " + name + "!"
title = None
message = greeting + title
print(message)Output:
TypeError: can only concatenate str (not 'NoneType') to strPython is explicit here: it tells you it expected a str but received a NoneType. The fix always involves ensuring the value is a string before concatenation.
Common Causes
Before jumping to solutions, it's important to understand where None values typically come from so you can prevent the error at its source.
1. Functions That Don't Return a Value
Any Python function that doesn't explicitly return something returns None by default:
def get_username(user_id):
if user_id == 1:
return "Alice"
username = get_username(2)
print("Welcome, " + username) # TypeError!2. Dictionary Lookups with .get()
The dict.get() method returns None when the key doesn't exist (unless you specify a default):
config = {"host": "localhost"}
port = config.get("port") # Returns None: key doesn't exist
connection_string = "Connecting to " + config.get("host") + ":" + port # TypeError!3. Variables Assigned Conditionally
Variables that are only assigned under certain conditions may remain None:
title = None
if some_condition:
title = "Manager"
message = "Title: " + title # TypeError if some_condition was False4. External Data Sources
Data from APIs, databases, CSV files, or user input can contain None or null values unexpectedly.
How to Fix It
Solution 1: Check for None Before Concatenating
The most explicit approach is to check whether the value is None and handle it accordingly:
title = None
if title is not None:
message = "Title: " + title
else:
message = "Title: Not Provided"
print(message)Output:
Title: Not ProvidedThis approach makes your intent clear and is easy to read.
Solution 2: Use the or Operator to Provide a Default
The or operator returns the first truthy value, which makes it a concise way to replace None (or any falsy value) with a default string:
title = None
message = "Title: " + (title or "Unknown")
print(message)Output:
Title: UnknownSolution 3: Use f-Strings (Recommended)
F-strings (Python 3.6+) automatically convert values to their string representation, so None becomes the string "None" instead of raising an error:
title = None
message = f"Title: {title}"
print(message)Output:
Title: NoneTo display a custom fallback instead of the word "None", combine f-strings with a ternary expression:
title = None
message = f"Title: {title if title is not None else 'Not Provided'}"
print(message)Output:
Title: Not ProvidedSolution 4: Use str.format()
The format() method behaves similarly to f-strings and handles None without raising an error:
title = None
message = "Title: {}".format(title if title is not None else "Not Provided")
print(message)Output:
Title: Not ProvidedSolution 5: Convert to String with str()
If you simply want None to appear as text (or want a universal conversion), wrap the variable in str():
title = None
message = "Title: " + str(title)
print(message)Output:
Title: NoneSolution 6: Fix the Source of None
Often the best fix is to prevent None from appearing in the first place. If a function can return None, update it to always return a string:
❌ Wrong: Function implicitly returns None:
def get_username(user_id):
if user_id == 1:
return "Alice"✅ Correct: Function always returns a string:
def get_username(user_id):
if user_id == 1:
return "Alice"
return "Guest" # Explicit default return valueFor dictionary lookups, always provide a default with .get():
config = {"host": "localhost"}
port = config.get("port", "5432")
connection_string = f"Connecting to {config.get('host')}:{port}"
print(connection_string)Output:
Connecting to localhost:5432Practical Example: Building a User Profile String
Here's a real-world scenario that combines multiple techniques:
def build_profile_summary(user):
"""Build a profile summary string, handling missing fields gracefully."""
name = user.get("name") or "Anonymous"
email = user.get("email") or "No email provided"
bio = user.get("bio")
summary = f"Name: {name}\n"
summary += f"Email: {email}\n"
summary += f"Bio: {bio if bio is not None else 'This user has not added a bio.'}"
return summary
user1 = {"name": "Alice", "email": "alice@example.com", "bio": "Python developer"}
print(build_profile_summary(user1))
print()
user2 = {"name": None, "email": None}
print(build_profile_summary(user2))Output:
Name: Alice
Email: alice@example.com
Bio: Python developer
Name: Anonymous
Email: No email provided
Bio: This user has not added a bio.Solutions at a Glance
| Approach | Example | Best For |
|---|---|---|
Check for None |
if x is not None: ... |
Explicit control flow |
or operator |
x or "default" |
Quick one-liner defaults |
| f-strings with ternary | f"{x if x is not None else 'default'}" |
Clean, readable formatting |
str() conversion |
str(x) |
Debugging / quick fixes |
| Fix the source | Return a default from functions | Preventing the problem entirely |
.get() with default |
dict.get(key, "default") |
Dictionary lookups |
Conclusion
The TypeError: can only concatenate str (not 'NoneType') to str error occurs whenever you try to use the + operator to join a string with a None value.
The best approach depends on your situation: use f-strings with a ternary expression for clean inline formatting, the or operator for quick defaults, or an explicit None check when you need more control.
However, the most robust fix is often to prevent None from reaching the concatenation in the first place, i.e. by ensuring your functions always return strings and your dictionary lookups include default values.