Skip to content

📋 Zero-Based Review of exceptions module before 1.0.0 #336

@sodre

Description

@sodre

Description

Conduct a zero-based review (ZBR) of the exceptions.py module before the 1.0.0 release to ensure the exception hierarchy, naming, and public API are correct and stable. Since 1.0.0 freezes the API, any breaking changes to exceptions must happen now.

Current Exception Hierarchy

ZAELimiterError (base)
├── RateLimitError
│   └── RateLimitExceeded          # noqa: N818 (not suffixed with Error)
├── InfrastructureError
│   ├── RateLimiterUnavailable     # noqa: N818 (not suffixed with Error)
│   ├── StackCreationError
│   │   └── StackAlreadyExistsError
│   └── InfrastructureNotFoundError
├── EntityError
│   ├── EntityNotFoundError
│   └── EntityExistsError
├── VersionError
│   ├── VersionMismatchError
│   └── IncompatibleSchemaError
└── ValidationError
    ├── InvalidIdentifierError
    └── InvalidNameError

Review Areas

Each area below should be evaluated and a decision recorded (keep, rename, restructure, or remove):

  1. Naming consistency: RateLimitExceeded and RateLimiterUnavailable both require # noqa: N818 because they don't end in Error. Decide whether to rename them (e.g., RateLimitExceededError, RateLimiterUnavailableError) or keep current names and document the convention.

  2. Hierarchy placement of RateLimiterUnavailable: It inherits from InfrastructureError, not RateLimitError. This means except RateLimitError does NOT catch unavailability. Verify this is intentional and document the rationale.

  3. StackCreationError scope: This exception is raised during both stack creation AND stack updates (used in stack_manager.py for update failures). Evaluate whether it should be renamed to StackOperationError or split into separate exceptions.

  4. ValidationError name collision: Shares a name with pydantic.ValidationError and django.core.exceptions.ValidationError. Evaluate whether this causes real confusion or is acceptable since it lives in the zae_limiter namespace.

  5. Backward-compat aliases (table_name): Both RateLimiterUnavailable and InfrastructureNotFoundError have self.table_name = self.stack_name. Decide whether to deprecate and remove these before 1.0.0 or keep them.

  6. Serialization consistency: Only RateLimitExceeded has as_dict() and retry_after_header. Decide whether other user-facing exceptions need serialization support.

  7. StackAlreadyExistsError as subclass of StackCreationError: Since it takes the same constructor args (including events it never uses), evaluate whether this inheritance is correct or if it should be a direct InfrastructureError subclass.

  8. Missing exception types: Check whether any error paths in the codebase raise generic Exception, ValueError, TypeError, or RuntimeError that should have dedicated library exceptions.

Acceptance Criteria

  • Each of the 8 review areas above has a documented decision (keep/change + rationale) in a comment on this issue
  • Any decided renames are implemented with backward-compatible aliases and DeprecationWarning
  • Any decided removals have DeprecationWarning added (if keeping for 1.0.0) or are removed (if breaking before 1.0.0)
  • __init__.py __all__ list matches the final set of public exceptions
  • Unit tests in tests/unit/ cover the exception hierarchy (isinstance checks for each category)
  • CLAUDE.md exception list matches the actual module contents

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions