Exception Hierarchy¶
Metaseed uses two distinct exception hierarchies serving different purposes.
Overview¶
| Hierarchy | Base Class | Location | Purpose |
|---|---|---|---|
| Internal | MiappeError |
core/exceptions.py |
Internal operations, legacy code |
| Public API | MetaseedError |
api/errors.py |
Public API boundary |
When to Use Which¶
Use MetaseedError (api/errors.py) when:¶
- Writing code in the public API layer (
api/module) - Raising errors that API consumers will catch
- Creating user-facing error messages
- Adding new exception types for the
MetaseedClientinterface
Use MiappeError (core/exceptions.py) when:¶
- Writing code in internal modules (
core/,models/,specs/,storage/) - Raising errors during spec loading, model generation, or validation
- Working with legacy code that already uses this hierarchy
Exception Flow¶
Internal exceptions are caught at the API boundary and re-raised as public exceptions:
Internal Layer Public API Layer
───────────────── ─────────────────
SpecError ──────────> ProfileNotFoundError
ModelError ──────────> EntityTypeNotFoundError
ValidationFailedError ────────> ValidationError
StorageIOError ──────────> (logged, re-raised as appropriate)
Internal Exceptions (MiappeError)¶
from metaseed.core.exceptions import SpecError, ModelError
# Raised when YAML spec is invalid
raise SpecError("Invalid field type 'unknown' in Investigation.title")
# Raised when model generation fails
raise ModelError("Circular dependency in entity definitions")
| Exception | When Raised |
|---|---|
SpecError |
Loading, parsing, or validating YAML specifications |
ModelError |
Generating, registering, or accessing Pydantic models |
ValidationFailedError |
Entity data fails validation rules |
StorageIOError |
File I/O errors during read/write operations |
Public API Exceptions (MetaseedError)¶
from metaseed.api.errors import ProfileNotFoundError, ValidationError
try:
client = MetaseedClient("nonexistent", "1.0")
except ProfileNotFoundError as e:
print(f"Profile not found: {e.profile}")
| Exception | When Raised |
|---|---|
ProfileNotFoundError |
Profile or version does not exist |
EntityNotFoundError |
Entity ID not found in store |
EntityTypeNotFoundError |
Entity type not in profile schema |
ValidationError |
Entity data fails validation |
Adding New Exceptions¶
- Determine the layer: internal operation or public API?
- Add to the appropriate module
- Inherit from the correct base class
- Include structured attributes (not just message strings)
- Document the exception in this file
Example for public API:
class DatasetNotFoundError(MetaseedError):
"""Dataset not found in storage."""
def __init__(self, dataset_id: str) -> None:
self.dataset_id = dataset_id
super().__init__(f"Dataset '{dataset_id}' not found")
Example for internal use: