Skip to main content

How to Resolve Python Error "TypeError: isinstance() arg 2 must be a type, tuple of types, or a union"

The isinstance() function is a fundamental tool in Python for checking an object's type. The TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union arises when the second argument provided to isinstance() is not what Python expects for type checking. Usually, this means you've passed a list or another non-type object instead of a single type object (like str, int, list) or a tuple containing type objects.

This guide explains the correct usage of isinstance()'s second argument and provides solutions for the common mistakes that lead to this error.

Understanding the Error: isinstance() Syntax

The isinstance() function checks if an object is an instance of a particular class or a subclass thereof. Its syntax is:

isinstance(object, classinfo)

  • object: The object whose type you want to check.
  • classinfo: This is where the error occurs. This argument must be either:
    • A single type object (e.g., int, str, list, dict, float, bool, a custom class name).
    • A tuple containing two or more type objects (e.g., (str, int), (list, tuple, set)). The function returns True if the object is an instance of any of the types in the tuple.
    note

    In modern Python with type hints, technically Union types can be involved, but the direct cause of this specific error message is usually providing something that isn't a type or a tuple of types.

The TypeError occurs because the value passed as the classinfo argument doesn't fit these requirements – most commonly, it's a list instance or another non-type object.

Cause 1: Passing a List Instead of a Tuple for Multiple Types

When checking if an object belongs to one of several possible types, you must provide those types within a tuple, not a list.

Error Scenario

value = 123
allowed_types_list = [str, int, float] # This is a LIST of types

print(f"Type of allowed_types_list: {type(allowed_types_list)}") # Output: <class 'list'>

try:
# ⛔️ TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union
# Passing the list directly as the second argument
if isinstance(value, allowed_types_list):
print("Value is of an allowed type.")
except TypeError as e:
print(e)

Output:

Type of allowed_types_list: <class 'list'>
isinstance() arg 2 must be a type or tuple of types
note

isinstance() does not accept a list for the classinfo argument.

Solution: Use a Tuple of Types

Provide the multiple types within a tuple () directly, or convert your list of types to a tuple using tuple().

value = 123
allowed_types_list = [str, int, float]

# ✅ Option 1: Convert the list to a tuple
allowed_types_tuple = tuple(allowed_types_list)
print(f"Type of allowed_types_tuple: {type(allowed_types_tuple)}") # Output: <class 'tuple'>
if isinstance(value, allowed_types_tuple):
print(f"Value {value} is an instance of one of {allowed_types_tuple} (using tuple conversion).") # This is executed
else:
print(f"Value {value} is not an instance (using tuple conversion).")

# ✅ Option 2 (Preferred): Use a tuple literal directly
if isinstance(value, (str, int, float)): # Pass tuple literal directly
print(f"Value {value} is an instance of one of (str, int, float) (using tuple literal).") # This is executed
else:
print(f"Value {value} is not an instance (using tuple literal).")

# Example with a string
another_value = "hello"
if isinstance(another_value, (str, int, float)):
print(f"Value '{another_value}' is an instance of one of (str, int, float).") # This is executed

Output:

Type of allowed_types_tuple: <class 'tuple'>
Value 123 is an instance of one of (<class 'str'>, <class 'int'>, <class 'float'>) (using tuple conversion).
Value 123 is an instance of one of (str, int, float) (using tuple literal).
Value 'hello' is an instance of one of (str, int, float).

Using a tuple literal (type1, type2, ...) directly is usually the clearest approach.

Cause 2: Shadowing Built-in Type Names

This error can also occur if you unintentionally assign a value (especially a list or other non-type object) to a variable that has the same name as a built-in type (like list, str, dict, int). This is called "shadowing."

Error Scenario

# ⚠️ Shadowing the built-in 'list' type with a variable assignment
list = ["apple", "banana"] # 'list' now refers to this specific list instance

my_data = [1, 2, 3]

print(f"Value of shadowed 'list': {list}")
# Output: Value of shadowed 'list': ['apple', 'banana']

print(f"Type of shadowed 'list': {type(list)}")
# Output: Type of shadowed 'list': <class 'list'> (Note: it's an instance!)

try:
# ⛔️ TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union
# Here, 'list' refers to the VARIABLE ["apple", "banana"], not the TYPE <class 'list'>
if isinstance(my_data, list):
print("my_data is a list.")
except TypeError as e:
print(e)

Output:

Value of shadowed 'list': ['apple', 'banana']
Type of shadowed 'list': <class 'list'>
isinstance() arg 2 must be a type or tuple of types

Because the name list was reassigned, it no longer refers to the built-in list type object that isinstance() expects. It refers to the actual list instance ["apple", "banana"].

The best and cleanest solution is to avoid shadowing built-in type names. Rename your variable to something descriptive that doesn't conflict.

# ✅ Renamed the variable to avoid shadowing
my_string_list = ["apple", "banana"] # Use a different name

my_data = [1, 2, 3]

# ✅ Now 'list' correctly refers to the built-in type
if isinstance(my_data, list):
print("my_data is a list (after renaming variable).") # This is executed
else:
print("my_data is not a list (after renaming variable).")
note

Always use distinct names for your variables to prevent hiding built-in functions or types.

Solution 2: Use type() to Get the Type (Workaround)

If renaming the variable is absolutely not feasible (which is rare and usually indicates a need for code refactoring), you can get the type of the shadowing variable using type() and pass that to isinstance().

# Scenario where 'list' variable shadows the type
list = ["apple", "banana"] # 'list' is the instance
my_data = [1, 2, 3]

# ✅ Workaround: Get the type of the shadowing variable
list_type_obj = type(list) # This correctly gets <class 'list'>
print(f"Type obtained via type(list): {list_type_obj}")
# Output: Type obtained via type(list): <class 'list'>

if isinstance(my_data, list_type_obj):
print("my_data is a list (using type() workaround).") # This is executed

# You could also get the type from a literal of the desired type:
if isinstance(my_data, type([])): # type([]) also returns <class 'list'>
print("my_data is a list (using type([]) workaround).") # This is executed

Output:

Type obtained via type(list): <class 'list'>
my_data is a list (using type() workaround).
my_data is a list (using type([]) workaround).
note

Why this is a workaround: While it prevents the TypeError, it makes the code less readable and hides the fact that a built-in name is being shadowed, which can lead to confusion elsewhere.

Renaming the variable is strongly preferred.

Debugging the Error

When isinstance() raises this TypeError:

  1. Focus on the second argument passed to isinstance().
  2. Print its value and type just before the isinstance() call:
    print(f"DEBUG: Arg 2 value: {repr(second_argument)}")
    print(f"DEBUG: Arg 2 type: {type(second_argument)}")
    # >> isinstance(obj, second_argument)
  3. If the type is list: You need to convert it to a tuple (tuple(second_argument)) or rewrite it as a tuple literal (type1, type2).
  4. If the type is NOT type or tuple: You've likely shadowed a built-in type name with a variable. Find the variable assignment and rename the variable.

Conclusion

The TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union occurs when the second argument provided to isinstance() is invalid for type checking.

The main solutions are:

  1. When checking against multiple types, provide them within a tuple (type1, type2, ...), not a list [type1, type2, ...].
  2. Avoid shadowing built-in type names (like list, str, dict, int) with your variable names. Rename conflicting variables (e.g., use my_list instead of list).

By ensuring the second argument to isinstance() is always a type object or a tuple of type objects, you can effectively use it for robust type checking in Python.