Skip to main content

How to Resolve "TypeError: can only concatenate str (not 'NoneType') to str" in Python

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

# Attempting to concatenate a string with None
message = greeting + title
print(message)

Output:

TypeError: can only concatenate str (not 'NoneType') to str

Python 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"
# No return statement for other IDs: returns None implicitly

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 False

4. 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 Provided

This 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: Unknown
caution

The or operator treats all falsy values the same: including empty strings "", 0, and False. If an empty string is a valid value in your use case, use an explicit if check or a ternary expression instead:

# This replaces "" with "Unknown", which may not be what you want
title = ""
result = title or "Unknown" # result is "Unknown"

# This preserves "" and only replaces None
result = title if title is not None else "Unknown" # result is ""

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: None

To 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 Provided

Solution 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 Provided

Solution 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: None
info

This approach is a quick fix but may not produce user-friendly output since it literally prints the word "None". Use this when debugging, but prefer a ternary expression or default value for production code.

Solution 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"
# Falls through and returns None for all other IDs

✅ Correct: Function always returns a string:

def get_username(user_id):
if user_id == 1:
return "Alice"
return "Guest" # Explicit default return value

For dictionary lookups, always provide a default with .get():

config = {"host": "localhost"}

# Provide a default value to avoid None
port = config.get("port", "5432")

connection_string = f"Connecting to {config.get('host')}:{port}"
print(connection_string)

Output:

Connecting to localhost:5432

Practical 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


# Complete user
user1 = {"name": "Alice", "email": "alice@example.com", "bio": "Python developer"}
print(build_profile_summary(user1))

print()

# User with missing fields
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

ApproachExampleBest For
Check for Noneif x is not None: ...Explicit control flow
or operatorx or "default"Quick one-liner defaults
f-strings with ternaryf"{x if x is not None else 'default'}"Clean, readable formatting
str() conversionstr(x)Debugging / quick fixes
Fix the sourceReturn a default from functionsPreventing the problem entirely
.get() with defaultdict.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.