Skip to main content

How to Resolve Python "ValueError: min()/max() arg is an empty sequence"

When using Python's built-in min() and max() functions to find the smallest or largest item in an iterable (like a list, tuple, or dictionary keys), you might encounter a ValueError: min() arg is an empty sequence or ValueError: max() arg is an empty sequence. This error occurs specifically when you pass an empty iterable to these functions without providing guidance on what to return in that case.

This guide explains why this ValueError happens and details the standard Pythonic ways to prevent or handle it using the default argument, preliminary checks, or try...except blocks.

Understanding the Error: Finding Extrema in Nothing

The min() and max() functions are designed to iterate through a sequence of items and determine the smallest or largest one based on comparison. If the sequence you provide contains no items (it's empty), there is logically no smallest or largest item to return. Python signals this impossible situation by raising a ValueError.

The Cause: Calling min() or max() on an Empty Sequence

The direct cause is passing an empty list, tuple, dictionary (which iterates over keys by default), set, or other iterable to min() or max() without specifying what the result should be in this empty case.

empty_list = []
empty_tuple = ()
empty_dict = {}

# Error Scenario with max()
try:
# ⛔️ ValueError: max() arg is an empty sequence
largest = max(empty_list)
print(largest)
except ValueError as e:
print(f"max() error: {e}")

# Error Scenario with min()
try:
# ⛔️ ValueError: min() arg is an empty sequence
smallest = min(empty_dict) # Iterating over an empty dict also yields nothing
print(smallest)
except ValueError as e:
print(f"min() error: {e}")

Both min() and max() accept an optional keyword argument named default. If the sequence is empty, the function will return the value provided to default instead of raising a ValueError. This is generally the cleanest and most direct way to handle potentially empty sequences.

empty_list = []
non_empty_list = [10, 5, 20]

# Using default with max()
max_result_empty = max(empty_list, default=0) # Return 0 if empty
print(f"Max of empty list with default=0: {max_result_empty}") # Output: 0

max_result_empty_none = max(empty_list, default=None) # Return None if empty
print(f"Max of empty list with default=None: {max_result_empty_none}") # Output: None

max_result_non_empty = max(non_empty_list, default=0) # List isn't empty, default ignored
print(f"Max of {non_empty_list} with default=0: {max_result_non_empty}") # Output: 20


# Using default with min()
min_result_empty = min(empty_list, default=-1) # Return -1 if empty
print(f"\nMin of empty list with default=-1: {min_result_empty}") # Output: -1

min_result_empty_none = min(empty_list, default=None) # Return None if empty
print(f"Min of empty list with default=None: {min_result_empty_none}") # Output: None

min_result_non_empty = min(non_empty_list, default=-1) # List isn't empty, default ignored
print(f"Min of {non_empty_list} with default=-1: {min_result_non_empty}") # Output: 5
note

Choose a default value that makes sense for your application logic (e.g., 0, None, float('inf'), float('-inf')).

Solution 2: Check if the Sequence is Empty Before Calling

You can explicitly check if the iterable contains any items before calling min() or max(). Python considers empty sequences "falsy" in a boolean context, so a simple if sequence: check works. Alternatively, use len().

my_list = []
result = None # Initialize result variable

# Check if list is not empty before calling max()
if my_list: # This evaluates to False for an empty list
result = max(my_list)
print(f"Max value: {result}")
else:
# This block runs
print("List is empty, cannot find max. Setting result to default.")
result = 0 # Or None, or handle as needed

print(f"Final result after check: {result}") # Output: 0

# Using len() explicitly
my_tuple = ()
if len(my_tuple) > 0:
result = min(my_tuple)
print(f"Min value: {result}")
else:
# This block runs
print("Tuple is empty, cannot find min.")
# result remains None (or assign another default)

This approach requires you to decide how to handle the empty case within the else block.

Solution 3: Use a try...except ValueError Block

You can attempt the min() or max() call and specifically catch the ValueError that occurs if the sequence is empty.

my_list = []
result = None # Initialize

try:
result = max(my_list)
print(f"Max found: {result}")
except ValueError:
# Handle the specific error for empty sequences
print("ValueError caught: List was empty. Setting result to default.")
result = 0 # Assign default value in the except block

print(f"Final result after try/except: {result}") # Output: 0

This clearly separates the normal operation from the error handling for the empty sequence case.

Applying to Dictionaries (and Other Iterables)

The error and solutions apply to any iterable. When min() or max() is called on a dictionary directly, it iterates over the keys. If the dictionary is empty, it raises the same ValueError.

empty_dict = {}
scores = {'Alice': 85, 'Bob': 92, 'Charlie': 78}

# Error with empty dict
try:
max_key = max(empty_dict)
except ValueError as e:
print(f"Error with empty dict: {e}") # Output: max() arg is an empty sequence

# Solutions for empty dict
max_key_default = max(empty_dict, default=None)
print(f"Max key (empty dict, default): {max_key_default}") # Output: None

# Works with non-empty dict
max_key_scores = max(scores) # Compares keys: 'Alice', 'Bob', 'Charlie'
print(f"Max key in scores: {max_key_scores}") # Output: Charlie

min_key_scores = min(scores, default=None)
print(f"Min key in scores: {min_key_scores}") # Output: Alice

# Note: To find min/max based on VALUES, iterate over scores.values()
max_score = max(scores.values(), default=0)
print(f"Max score value: {max_score}") # Output: 92

The default argument, length check, and try/except methods all work correctly with empty dictionaries as well.

How min() and max() Work

  • max(iterable, *, default=obj) / min(iterable, *, default=obj): Returns the largest/smallest item in a non-empty iterable.
  • max(arg1, arg2, *args) / min(arg1, arg2, *args): Returns the largest/smallest of two or more arguments.
  • default Keyword Argument: If the iterable provided to the first form is empty, the default value is returned. If default is not provided and the iterable is empty, ValueError is raised.

Conclusion

The ValueError: min()/max() arg is an empty sequence occurs when you try to find the minimum or maximum of an iterable that contains no elements.

The recommended and most Pythonic way to prevent this is to use the default keyword argument:

result = max(my_sequence, default=some_sensible_default)
result = min(my_sequence, default=some_sensible_default)

Alternatives include:

  • Checking if the sequence is non-empty before calling (if my_sequence: or if len(my_sequence) > 0:).
  • Wrapping the call in a try...except ValueError block.

Choose the method that best fits the clarity and logic of your specific situation. Using default is often the most concise solution when a sensible default value exists.