Skip to content

POC: Exception Hierarchy for Mesa 4.0#3197

Merged
quaquel merged 15 commits intomesa:mainfrom
Nithurshen:feat/exception-hierarchy
Feb 25, 2026
Merged

POC: Exception Hierarchy for Mesa 4.0#3197
quaquel merged 15 commits intomesa:mainfrom
Nithurshen:feat/exception-hierarchy

Conversation

@Nithurshen
Copy link
Copy Markdown
Contributor

@Nithurshen Nithurshen commented Jan 23, 2026

Summary

This PR introduces a standardized exception hierarchy for Mesa 4.0, acting as a Proof of Concept (POC) for the architectural proposal discussed recently. It adds a new mesa.errors module containing a base MesaError class and refactors SingleGrid to use a specific CellNotEmptyError instead of a generic Exception.

Motive

Currently, Mesa relies heavily on generic Python exceptions (like Exception or ValueError) for simulation logic failures. This makes it difficult for users to programmatically handle simulation errors without risking the suppression of unrelated system errors (like KeyboardInterrupt or MemoryError).

By introducing a dedicated hierarchy rooted in MesaError, we allow users to write cleaner, safer error-handling code. This PR demonstrates this pattern by fixing the "Cell not empty" error in SingleGrid, which was previously raising a raw Exception.

Implementation

  1. New Module: Created mesa/exceptions.py.
  2. Base Class: Defined MesaException(Exception) as the root for all Mesa-specific exceptions.

Additional Notes

  • This is a Proof of Concept. If approved, subsequent PRs can migrate other parts of the codebase to this hierarchy incrementally.

@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 -2.4% [-3.5%, -1.2%] 🔵 -0.7% [-0.9%, -0.6%]
BoltzmannWealth large 🔵 +2.4% [-7.5%, +12.9%] 🟢 -7.4% [-10.7%, -4.5%]
Schelling small 🔵 -1.2% [-1.6%, -0.7%] 🔵 -0.5% [-0.6%, -0.4%]
Schelling large 🔵 +2.0% [-4.2%, +7.9%] 🔵 +1.1% [-2.2%, +4.3%]
WolfSheep small 🟢 -7.0% [-9.6%, -4.4%] 🔵 -2.1% [-2.5%, -1.6%]
WolfSheep large 🔵 -12.9% [-23.4%, -1.7%] 🟢 -12.1% [-16.0%, -8.4%]
BoidFlockers small 🔵 -3.5% [-4.3%, -2.6%] 🔵 -0.7% [-0.8%, -0.5%]
BoidFlockers large 🔵 +2.6% [+0.7%, +5.2%] 🔵 -0.2% [-0.5%, +0.1%]

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 23, 2026

Thanks for this PR. I think its still a bit premature. I don't agree with mesa.errors.py, and mesa.space is a bad choice to start with because it's about to be removed.

Also CellNotEmptyError is not a good name. I prefer Exception over Error. Also, the issue for at least discrete_space is not that the cell is not empty. Rather, It is that the cell is at capacity. So CellFullException might be more on point.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 23, 2026

Thanks for the update. I think this is moving in a good direction.

What other generic exceptions should be replaced in mesa.discrete_space.

@Nithurshen
Copy link
Copy Markdown
Contributor Author

Thanks.
I have three additional candidates for replacement in mind within mesa.discrete_space (AgentMissingException, CellMissingException, and ConnectionMissingException).

I have posted the detailed breakdown and rationale for these additions in the main Discussion thread.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 24, 2026

I have three additional candidates for replacement in mind within mesa.discrete_space (AgentMissingException, CellMissingException, and ConnectionMissingException).

Sounds good to me. Where possible, consider using the raise from syntax. For example, the key error cases could use this. Basically, this wraps the source (key error) inside our more informative custom exception. Please feel free to add these to this PR.

@Nithurshen
Copy link
Copy Markdown
Contributor Author

I have three additional candidates for replacement in mind within mesa.discrete_space (AgentMissingException, CellMissingException, and ConnectionMissingException).

Sounds good to me. Where possible, consider using the raise from syntax. For example, the key error cases could use this. Basically, this wraps the source (key error) inside our more informative custom exception. Please feel free to add these to this PR.

Done

@Nithurshen
Copy link
Copy Markdown
Contributor Author

Nithurshen commented Jan 25, 2026

@EwoutH,
I am thinking of PropertyLayerDimensionException, DuplicatePropertyLayerException, and InvalidRadiusException again for mesa.discrete_space.
I have updated the discussion thread in detail. Kindly let me know your opinion.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 25, 2026

Just a kind request: please refrain from pinging maintainers. We get the updates and try to respond as soon as we can. Sometimes, we as maintainers might ping each other because we are aware of our respective expertise across different parts of the codebase.

@Nithurshen
Copy link
Copy Markdown
Contributor Author

As discussed in the thread,
MesaSpaceException, and DimensionException has been implemented.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 30, 2026

I like the direction this is moving in. Can you next take a look at the experimental continouous space and see what custom exception needs there might be there and how those might be integrated cleanly into this hierarchy?

@Nithurshen
Copy link
Copy Markdown
Contributor Author

If we establish DimensionException as a shared/generic error, ContinuousSpace fits in cleanly. I propose adding a ContinuousSpaceException base class and one specific logic error:

Proposed Hierarchy

MesaException
├── DimensionException (Shared: used for invalid width/height or grid shape mismatches)
├── DiscreteSpaceException
│   └── ... (CellFull, etc.)
└── ContinuousSpaceException (New Module Base)
    └── OutOfBoundsException

Rationale for OutOfBoundsException:
In a continuous space with torus=False, agents often hit the edge. Currently, we might rely on clamping or generic errors.
• Use Case: A user wants custom boundary logic (e.g., "if agent hits wall, reverse velocity" or "if agent hits wall, remove agent").
• Benefit: They can catch OutOfBoundsException to trigger this logic cleanly, rather than checking coordinates manually after every move step.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 31, 2026

Do we need the distinction between ContinuousSpaceException and DiscreteSpaceException, or can we simplify this to just a generic SpaceException?

I'll get back to you on theOutOfBoundsException.

@Nithurshen
Copy link
Copy Markdown
Contributor Author

Nithurshen commented Jan 31, 2026

Do we need the distinction between ContinuousSpaceException and DiscreteSpaceException, or can we simplify this to just a generic SpaceException?

How about, as of now we implement all the exceptions we want under ContinousSpaceException and DiscreteSpaceException, then judging the number of exceptions under each branch, we decide if we want a unified SpaceException.
Or another option is, we implement SpaceException, and make ContinousSpaceException and DiscreteSpaceException inherit from it. But I think this option will make the hierarchy more complicated.

I'll get back to you on theOutOfBoundsException.

Sure.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 31, 2026

Do we need a separate ContinuousSpaceException and DiscreteSpaceException?

@quaquel quaquel added the enhancement Release notes label label Feb 1, 2026
@Nithurshen
Copy link
Copy Markdown
Contributor Author

Do we need a separate ContinuousSpaceException and DiscreteSpaceException?

I don't think we will need separate exceptions. I have implemented a unified SpaceException to take care of this.

super().__init__(f"Cell at coordinate {coordinate} is full.")


class AgentMissingException(SpaceException):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

there are other places that this might be used (e.g., model.deregister_agent), so this might subclass mesaexception, rather than space exception.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Feb 15, 2026

@EwoutH, I am happy with how this is turning out and would be in favor of merging this as part of 4.0 while expanding the use of custom exceptions where appropriate. Would like to hear your thoughts as well before merging this.

@quaquel quaquel merged commit 4144b0a into mesa:main Feb 25, 2026
11 of 12 checks passed
@EwoutH
Copy link
Copy Markdown
Member

EwoutH commented Feb 25, 2026

Sorry, missed it last week. But it looks good and clean, thanks both!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Release notes label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants