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}")
Solution 1: Provide the default
Keyword Argument (Recommended)
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
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-emptyiterable
.max(arg1, arg2, *args)
/min(arg1, arg2, *args)
: Returns the largest/smallest of two or more arguments.default
Keyword Argument: If theiterable
provided to the first form is empty, thedefault
value is returned. Ifdefault
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:
orif 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.