ZhuLinsen/daily_stock_analysis · error · AlertNotFoundError

not_found

not_found

Error message

Alert rule not found: {rule_id}

What it means

AlertNotFoundError (subclass of AlertServiceError, itself a ValueError) raised in AlertService.get_rule (src/services/alert_service.py:117) when AlertRepository.get_rule returns no row for the given rule_id — i.e. no alert rule with that primary key exists (or it was deleted). It carries code 'not_found' semantics for the API layer to map to HTTP 404.

Source

Thrown at src/services/alert_service.py:117

    error_code = "unsupported_alert_type"


class AlertService:
    """Business logic for alert rule CRUD and dry-run evaluation."""

    def __init__(self, db_manager: Optional[DatabaseManager] = None):
        self.db = db_manager or DatabaseManager.get_instance()
        self.repo = AlertRepository(self.db)

    def create_rule(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        fields = self._normalize_rule_payload(payload)
        return self._serialize_rule(self.repo.create_rule(fields))

    def get_rule(self, rule_id: int) -> Dict[str, Any]:
        row = self.repo.get_rule(rule_id)
        if row is None:
            raise AlertNotFoundError(f"Alert rule not found: {rule_id}")
        return self._serialize_rule(row)

    def update_rule(self, rule_id: int, payload: Dict[str, Any]) -> Dict[str, Any]:
        row = self.repo.get_rule(rule_id)
        if row is None:
            raise AlertNotFoundError(f"Alert rule not found: {rule_id}")
        if not payload:
            raise AlertServiceError("No fields provided for update")
        self._validate_rule_update_payload(payload)

        merged = self._serialize_rule_base(row)
        merged.update(payload)
        fields = self._normalize_rule_payload(merged, source=merged.get("source") or "api")
        updated = self.repo.update_rule(rule_id, fields)
        if updated is None:
            raise AlertNotFoundError(f"Alert rule not found: {rule_id}")
        return self._serialize_rule(updated)

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. List rules (list_rules / GET collection) to see current ids and re-fetch the correct one.
  2. Handle 404/AlertNotFoundError in the client by refreshing the rule list and dropping the stale entry.
  3. Verify you are pointed at the right environment/database for the id you hold.

Example fix

# before
rule = service.get_rule(123)  # KeyError-style crash if deleted

# after
try:
    rule = service.get_rule(123)
except AlertNotFoundError:
    rules = service.list_rules(page=1, page_size=50)
    rule = next((r for r in rules['items'] if ...), None)
Defensive patterns

Strategy: try-catch

Validate before calling

rules = service.list_rules(page=1, page_size=200)
known_ids = {r['id'] for r in rules['items']}
if rule_id not in known_ids:
    return not_found(f'rule {rule_id} not in current list')

Try / catch

from src.services.alert_service import AlertNotFoundError
try:
    rule = service.get_rule(rule_id)
except AlertNotFoundError:
    return JSONResponse(status_code=404, content={'detail': f'alert rule {rule_id} not found'})

Prevention

When it happens

Trigger: GET /api/alerts/rules/{rule_id} with an id that never existed or was deleted; a stale rule_id held in the frontend after another tab/session removed it; an id from a different database/environment (dev id used against prod).

Common situations: Cached UI lists referencing deleted rules; database reset/reseed while clients keep old ids; typos in manual curl/scripts; concurrent delete-then-read races.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/77f02330d7fa4d62. Report an issue: GitHub.