Skip to content

fix: prevent IndexError and add clear error message in select_random_empty_cell() when grid is full#3500

Merged
quaquel merged 4 commits intomesa:mainfrom
BEASTSHRIRAM:fixbug
Mar 11, 2026
Merged

fix: prevent IndexError and add clear error message in select_random_empty_cell() when grid is full#3500
quaquel merged 4 commits intomesa:mainfrom
BEASTSHRIRAM:fixbug

Conversation

@BEASTSHRIRAM
Copy link
Copy Markdown
Contributor

@BEASTSHRIRAM BEASTSHRIRAM commented Mar 10, 2026

Summary

Fixes a crash in Grid.select_random_empty_cell() when the grid is completely full by wrapping random.choice() in a try-catch block and raising a clear ValueError instead of a cryptic IndexError.

Bug / Issue

Fixes #3014

When a user's agent-based model fills a grid to 100% capacity and calls select_random_empty_cell(), the method crashes with an unhelpful error:

IndexError: Cannot choose from an empty sequence

This happens because the heuristic tries 50 random cell selections (all fail on a full grid), then falls back to np.argwhere(self.property_layers["empty"]) which returns an empty array. When random.choice() is called on an empty array, it raises IndexError, leaving users confused about what went wrong.

Implementation

Wrapped self.random.choice(empty_coords) in a try-except block in Grid.select_random_empty_cell() (mesa/discrete_space/grid.py) to catch IndexError and raise a clear ValueError with proper exception chaining.

Code change:

empty_coords = np.argwhere(self.property_layers["empty"])
try:
    random_coord = self.random.choice(empty_coords)
except IndexError as e:
    raise ValueError(
        "Grid is completely full. No empty cells available. "
        "Cannot select a random empty cell."
    ) from e
return self._cells[tuple(random_coord)]

This approach follows the EAFP (Easier to Ask for Forgiveness than Permission) principle, is more Pythonic, and provides better exception chaining for debugging.

Testing

Added unit test test_infinite_loop_on_full_grid() in test_discrete_space.py that fills a 2×2 grid completely and asserts that the new ValueError with the descriptive message is raised.

Verified test passes with the implementation.

Additional Notes

This change creates a better Developer Experience (DX) by "failing fast" with an explicit, actionable error message rather than crashing deep in the code with a cryptic exception. Users immediately understand that their grid is full and can adjust their model parameters accordingly (more cells, faster agent movement, etc.).

No breaking API changes — only the error type changed, which improves clarity without reducing functionality.

@github-actions

This comment was marked as outdated.

@BEASTSHRIRAM
Copy link
Copy Markdown
Contributor Author

Hi! I was going through the project setup and noticed that Docker is mentioned in readme. I use Docker quite often, but I couldn’t find a docker-compose.yml file in the repository.
Would you like me to create one for the project? I’d be happy to work on setting it up if needed.

Copy link
Copy Markdown
Member

@quaquel quaquel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last suggestion. Also, please ensure that the PR description is up to date.

@quaquel quaquel added trigger-benchmarks Special label that triggers the benchmarking CI enhancement Release notes label labels Mar 11, 2026
@BEASTSHRIRAM
Copy link
Copy Markdown
Contributor Author

Done! ThankYou @quaquel

@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 -0.9% [-1.1%, -0.7%] 🔵 -0.7% [-0.9%, -0.5%]
BoltzmannWealth large 🔵 -1.8% [-2.1%, -1.4%] 🔵 +0.1% [-0.3%, +0.5%]
Schelling small 🔵 -1.1% [-1.3%, -0.9%] 🔵 +0.1% [-0.0%, +0.3%]
Schelling large 🔵 +0.0% [-0.5%, +0.7%] 🔵 +2.4% [+1.7%, +3.0%]
WolfSheep small 🔵 -1.0% [-1.2%, -0.9%] 🔵 -0.4% [-0.5%, -0.2%]
WolfSheep large 🔵 -1.5% [-2.2%, -0.9%] 🔵 +0.1% [-0.5%, +0.6%]
SugarscapeG1mt small 🔵 -0.6% [-1.2%, -0.0%] 🔵 +1.6% [+0.6%, +2.7%]
SugarscapeG1mt large 🔵 -1.9% [-2.3%, -1.4%] 🔵 -0.6% [-0.9%, -0.3%]
BoidFlockers small 🔵 -1.9% [-2.1%, -1.6%] 🔵 -2.4% [-2.8%, -2.1%]
BoidFlockers large 🔵 -2.0% [-2.3%, -1.7%] 🔵 -1.4% [-1.6%, -1.2%]

@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 +1.2% [+0.8%, +1.6%] 🔵 +0.3% [+0.1%, +0.5%]
BoltzmannWealth large 🔵 +0.6% [-0.2%, +1.4%] 🔵 -0.0% [-1.5%, +1.3%]
Schelling small 🔵 +0.6% [+0.0%, +1.2%] 🔵 +0.3% [+0.0%, +0.5%]
Schelling large 🔵 +0.6% [+0.1%, +1.2%] 🔵 +0.1% [-2.2%, +2.3%]
WolfSheep small 🔵 -3.2% [-4.1%, -2.2%] 🔵 -1.5% [-1.9%, -1.1%]
WolfSheep large 🔵 +0.9% [-0.9%, +2.6%] 🔵 +0.2% [-1.8%, +2.7%]
SugarscapeG1mt small 🔵 +2.9% [+2.2%, +3.6%] 🔵 +1.5% [+1.2%, +1.8%]
SugarscapeG1mt large 🔵 +2.1% [+0.6%, +3.5%] 🔵 +0.6% [-0.1%, +1.2%]
BoidFlockers small 🔵 -1.4% [-1.8%, -1.0%] 🔵 -0.1% [-0.3%, +0.0%]
BoidFlockers large 🔵 -1.0% [-1.4%, -0.5%] 🔵 -0.4% [-0.6%, -0.1%]

@quaquel quaquel merged commit 0eaf588 into mesa:main Mar 11, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Release notes label trigger-benchmarks Special label that triggers the benchmarking CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants