Raise exceptions instead of returning None, logging warnings, or silently modifying values when encountering error conditions. This makes failures explicit and forces callers to handle error cases properly, improving code reliability and debugging experience.

Why this matters:

Apply this by:

Example:

# โŒ Avoid - silent failure
def update_schedule(session: Session, schedule_id: str, updates: dict) -> Optional[WorkflowSchedulePlan]:
    schedule = session.get(WorkflowSchedulePlan, schedule_id)
    if not schedule:
        return None  # Forces caller to check for None

# โœ… Prefer - explicit exception
def update_schedule(session: Session, schedule_id: str, updates: dict) -> WorkflowSchedulePlan:
    schedule = session.get(WorkflowSchedulePlan, schedule_id)
    if not schedule:
        raise ValueError(f"Schedule not found: {schedule_id}")
    # ... rest of implementation

Exception: Use None returns only when the absence of a value is a valid business case, not an error condition.