-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CellCollection.select_random_agent() crashes when no agents in cells #2982
Description
I was building a simple money exchange model where agents on a grid give money to random neighbors. My model kept crashing and I tracked it down to CellCollection.select_random_agent() raising IndexError when there are no agents in the cells.
This happens in sparse grids or when agents die/move, leaving neighborhoods empty. The method tries to call random.choice() on an empty list, which crashes the entire model.
Location: mesa/discrete_space/cell_collection.py, line 111
Expected behavior
The method should either:
- Raise a more descriptive error explaining no agents are available, OR
- Have a parameter to handle empty cases gracefully
Currently it just crashes with a generic IndexError that doesn't explain the real problem.
To Reproduce
Here's a minimal example showing the crash:
from mesa import Model
from mesa.discrete_space import OrthogonalMooreGrid, CellAgent
class MoneyAgent(CellAgent):
def __init__(self, model, cell):
super().__init__(model)
self.cell = cell
self.wealth = 100
def step(self):
if self.wealth > 0:
# This crashes when neighborhood is empty!
other = self.cell.neighborhood.select_random_agent()
other.wealth += 1
self.wealth -= 1
class MoneyModel(Model):
def __init__(self, n_agents=5, width=10, height=10):
super().__init__()
self.grid = OrthogonalMooreGrid((width, height), random=self.random)
# Sparse grid - most cells empty
for _ in range(n_agents):
cell = self.random.choice(list(self.grid.all_cells))
MoneyAgent(self, cell)
def step(self):
self.agents.shuffle_do("step")
# Run it
model = MoneyModel()
model.step() # Crashes!Error Output:
Traceback (most recent call last):
File "test_crash_real.py", line 52, in <module>
model.step()
File "mesa/model.py", line 136, in _wrapped_step
self._user_step(*args, **kwargs)
File "test_crash_real.py", line 41, in step
self.agents.shuffle_do("step")
File "mesa/agent.py", line 356, in shuffle_do
getattr(agent, method)(*args, **kwargs)
File "test_crash_real.py", line 21, in step
other = self.cell.neighborhood.select_random_agent()
File "mesa/discrete_space/cell_collection.py", line 111, in select_random_agent
return self.random.choice(list(self.agents))
File "random.py", line 347, in choice
raise IndexError('Cannot choose from an empty sequence')
IndexError: Cannot choose from an empty sequence
Root Cause
Looking at the code in cell_collection.py:
def select_random_agent(self) -> CellAgent:
"""Select a random agent."""
return self.random.choice(list(self.agents)) # Crashes if empty!When self.agents is empty (no agents in the cells), list(self.agents) returns [], and random.choice([]) raises IndexError.
Proposed Fix
def select_random_agent(self) -> CellAgent:
"""Select a random agent."""
agents_list = list(self.agents)
if not agents_list:
raise ValueError("No agents available in the cell collection")
return self.random.choice(agents_list)I'm happy to submit a PR if this looks like a valid issue.