{"record":{"id":"289ae0615d45922c","repo":"ZhuLinsen/daily_stock_analysis","slug":"invalid-alert-type-rule-get-alert-type","errorCode":null,"errorMessage":"invalid alert_type: {rule.get('alert_type')}","messagePattern":"invalid alert_type: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agent/events.py","lineNumber":475,"sourceCode":"            f\"invalid entries at positions: {invalid_indices}\"\n        )\n\n    return parsed\n\n\ndef validate_event_alert_rule(rule: Dict[str, Any]) -> None:\n    \"\"\"Validate one serialized EventMonitor rule.\"\"\"\n    if not isinstance(rule, dict):\n        raise ValueError(\"Event alert rule must be an object\")\n\n    stock_code = str(rule.get(\"stock_code\") or \"\").strip()\n    if not stock_code:\n        raise ValueError(\"stock_code is required\")\n\n    try:\n        alert_type = AlertType(rule.get(\"alert_type\", \"\"))\n    except ValueError as exc:\n        raise ValueError(f\"invalid alert_type: {rule.get('alert_type')}\") from exc\n    _ensure_runtime_supported_alert_type(alert_type)\n\n    status = rule.get(\"status\")\n    if status is not None:\n        try:\n            AlertStatus(status)\n        except ValueError as exc:\n            raise ValueError(f\"invalid status: {status}\") from exc\n\n    ttl_hours = rule.get(\"ttl_hours\")\n    if ttl_hours is not None:\n        try:\n            ttl_value = float(ttl_hours)\n        except (TypeError, ValueError) as exc:\n            raise ValueError(f\"invalid ttl_hours: {ttl_hours}\") from exc\n        if ttl_value <= 0:\n            raise ValueError(\"ttl_hours must be > 0\")\n","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/agent/events.py#L457-L493","documentation":"Raised when rule['alert_type'] cannot be mapped to the AlertType enum (valid values: price_cross, price_change_percent, volume_spike, sentiment_shift, risk_flag, custom). The constructor AlertType(rule.get('alert_type', '')) raises ValueError, which is re-wrapped with the offending value in the message. Note that even a valid enum name like PRICE_CROSS fails here because AlertType is a str-Enum constructed from values, not names.","triggerScenarios":"validate_event_alert_rule with alert_type missing (defaults to ''), misspelled ('price-cross', 'pricecross'), uppercase enum name ('PRICE_CROSS'), or any string outside the six enum values. Also triggered by non-string values like None or 1.","commonSituations":"Hand-written rule JSON copied from docs that use the enum member name instead of the snake_case value; LLM-generated rules inventing type names; schema drift after a new AlertType was added but stored rules use an old/newer vocabulary; frontend dropdown using labels instead of values.","solutions":["Set alert_type to one of the exact enum values: 'price_cross', 'price_change_percent', 'volume_spike', 'sentiment_shift', 'risk_flag', 'custom'.","Check stored/persisted rules for stale or renamed type strings and migrate them.","If the value came from an LLM, constrain generation with an enum list in the prompt or validate against AlertType before persisting."],"exampleFix":"// before\nrule = {\"stock_code\": \"AAPL\", \"alert_type\": \"PRICE_CROSS\", \"price\": 200}\n# ValueError: invalid alert_type: PRICE_CROSS\n\n// after\nrule = {\"stock_code\": \"AAPL\", \"alert_type\": \"price_cross\", \"price\": 200}\nvalidate_event_alert_rule(rule)","handlingStrategy":"validation","validationCode":"from src.agent.events import AlertType\n\ndef normalize_alert_type(raw) -> str | None:\n    try:\n        return AlertType(str(raw).strip().lower()).value\n    except ValueError:\n        return None\n\n# before validating:\n# if normalize_alert_type(rule.get(\"alert_type\")) is None: reject","typeGuard":"def is_supported_alert_type(raw: object) -> bool:\n    return normalize_alert_type(raw) is not None","tryCatchPattern":"try:\n    validate_event_alert_rule(rule)\nexcept ValueError as e:\n    if str(e).startswith(\"invalid alert_type\"):\n        rule[\"alert_type\"] = repair_or_default_type(rule)  # or reject\n    else:\n        raise","preventionTips":["Always use enum values (snake_case), not member names (PRICE_CROSS).","Expose AlertType values in UI dropdowns and LLM prompts via [t.value for t in AlertType].","Migrate stored rules when the AlertType vocabulary changes."],"tags":["validation","event-monitor","enum","alert-type"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}