Skip to main content

How to Solve "TypeError: can only join an iterable" in Python

The error TypeError: can only join an iterable occurs when you call the str.join() method with a non-iterable value as its argument. The join() method requires an iterable (like a list, tuple, or set) of strings.

This guide explains the error and provides the correct ways to use join().

Understanding str.join() and Iterables

The str.join() method is used to concatenate strings from an iterable into a single string, using the string on which join() is called as a separator. An iterable is any object that can be looped over, such as:

  • Lists: ['apple', 'banana', 'cherry']
  • Tuples: ('apple', 'banana', 'cherry')
  • Sets: {'apple', 'banana', 'cherry'} (order is not guaranteed)
  • Strings: 'apple' (iterates over characters)
  • Dictionary keys: my_dict.keys() (iterates over keys)
  • Dictionary values: my_dict.values() (iterates over values)
  • Dictionary items: my_dict.items() (iterates over (key, value) tuples)
  • Generators: (x for x in range(5))

Incorrect Usage:

# ⛔️ TypeError: can only join an iterable
# my_str = ','.join(None) # None is not iterable
# my_str = ','.join(123) # Integers are not iterable
# my_str = ', '.join(True) # Booleans are not iterable

Correct Usage:

my_str = ','.join(['apple', 'banana', 'cherry'])  # List (iterable)
print(my_str) # Output: apple,banana,cherry

my_str = '-'.join(('a', 'b', 'c')) # Tuple (iterable)
print(my_str) # Output: a-b-c

my_str = ''.join({'x', 'y', 'z'}) # Set (iterable, but order not guaranteed)
print(my_str) # Output: (order is not guaranteed)

Common Causes of the Error

Passing None to join()

The most frequent cause is accidentally passing None to join():

my_list = None  #  Could be the result of a function call, etc.

# ⛔️ TypeError: can only join an iterable
# my_str = ','.join(my_list)

Common Sources of None

  • Functions that don't return a value: A function that has no explicit return statement implicitly returns None. If you call such a function and pass its result to join(), you'll get the error.

    # 👇️ This function returns None
    def get_list():
    print(['kiwi', 'banana', 'apple'])

    # ⛔️ TypeError: can only join an iterable
    # my_str = ' '.join(get_list())
    • The function needs to return an iterable for it to work.
      def get_list():
      return ['kiwi', 'banana', 'apple']
      my_str = ' '.join(get_list())
      print(my_str) # Output: kiwi banana apple
  • Methods that modify in place: Many list methods (like sort(), reverse(), append()) modify the list in place and return None.

    fruits = ['kiwi', 'banana', 'apple']
    new_list = fruits.reverse()
    print(new_list) # 👉️ None

    # ⛔️ TypeError: can only join an iterable
    #my_str = ','.join(new_list)
    • You must first call the method to modify the list, and then pass the list object to the join() function.
  • Conditional returns: A function might return a list only under certain conditions, and None otherwise.

    def get_list(a):
    if len(a) > 3:
    return a

    # TypeError: can only join an iterable
    #my_str = ''.join(get_list([1,2])) # Returns None
    • You must always make sure to return an iterable.

Passing a Non-Iterable Value

Passing any value that is not an iterable, like an integer, a boolean or a single string, will cause the error:

# ⛔️ TypeError: can only join an iterable
# my_str = ','.join(123) # 123 is not iterable
# my_str = ','.join(True) # Boolean is not iterable
# my_str = ','.join('abc') # String is iterable, this will work.

Solutions and Best Practices

Always Pass an Iterable

The fundamental solution is to always ensure you're passing an iterable of strings to join(). If you're unsure, use isinstance() to check:

my_variable = ['a', 'b', 'c']  # Could be anything

if isinstance(my_variable, (list, tuple, set, str)): # Check if it is a sequence
result = ','.join(my_variable)
print(result)
else:
print("Error: my_variable is not iterable")
# Or raise a TypeError, or handle it some other way
  • isinstance(my_variable, (list, tuple, set, str)): This checks if my_variable is an instance of any of the listed types. This is a good, robust check.

Checking for None Before Joining

If your variable might be None, check for that before calling join():

my_list = None  # Or some function that might return None

if my_list is not None:
result = ','.join(my_list)
print(result)
else:
result = "" # Or some other default
print("my_list was None. Using empty string.")

# OR, more concisely using the conditional operator

result = ','.join(my_list) if my_list is not None else ''

Ensure Functions Return Iterables

If you're calling a function that's supposed to return a list (or other iterable), make sure it always does, even in error cases:

def get_items():
try:
# ... some code that might fail ...
return ['item1', 'item2', 'item3']
except SomeError:
print("An error occurred!")
return [] # Return an EMPTY LIST on error, not None
result = ', '.join(get_items()) # safe

Conclusion

The TypeError: can only join an iterable error in Python is a clear indication that you're using str.join() incorrectly.

  • Always pass an iterable of strings to join().
  • If there's a possibility of None, check for it explicitly.
  • If a function is supposed to return an iterable, make sure it always does so, even in error cases.

By following these guidelines, you can avoid this common error and write more reliable Python code.