{"record":{"id":"9c6cf77a86ab6f5a","repo":"ZhuLinsen/daily_stock_analysis","slug":"validation-error-9c6cf7","errorCode":"validation_error","errorMessage":"unsupported market alert_type: {alert_type}","messagePattern":"unsupported market alert_type: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"src/services/market_light_alerts.py","lineNumber":52,"sourceCode":"class MarketLightAlert:\n    \"\"\"Runtime alert for market-level Market Light rules.\"\"\"\n\n    target_scope: str\n    target: str\n    alert_type: str\n    parameters: Dict[str, Any]\n    metadata: Dict[str, Any] = field(default_factory=dict)\n    description: str = \"\"\n    stock_code: str = \"\"\n\n    def __post_init__(self) -> None:\n        self.target = normalize_market_alert_region(self.target)\n        self.stock_code = self.target\n\n\ndef normalize_market_alert_parameters(alert_type: str, parameters: Dict[str, Any]) -> Dict[str, Any]:\n    if alert_type not in MARKET_ALERT_TYPES:\n        raise ValueError(f\"unsupported market alert_type: {alert_type}\")\n    if not isinstance(parameters, dict):\n        raise ValueError(\"parameters must be an object\")\n\n    if alert_type == \"market_light_status\":\n        raw_statuses = parameters.get(\"statuses\")\n        if raw_statuses is None:\n            raw_statuses = [\"red\", \"yellow\"]\n        if isinstance(raw_statuses, str):\n            raw_statuses = [raw_statuses]\n        if not isinstance(raw_statuses, list) or not raw_statuses:\n            raise ValueError(\"market_light_status statuses must be a non-empty list\")\n        statuses = []\n        for raw_status in raw_statuses:\n            status = str(raw_status or \"\").strip().lower()\n            if status not in MARKET_STATUS_VALUES:\n                raise ValueError(\"market_light_status statuses only supports red or yellow\")\n            if status not in statuses:\n                statuses.append(status)","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/market_light_alerts.py#L34-L70","documentation":"ValueError(f'unsupported market alert_type: {alert_type}') with code validation_error is raised by normalize_market_alert_parameters (src/services/market_light_alerts.py:53) when the alert_type is not in MARKET_ALERT_TYPES = {'market_light_status', 'market_light_score_drop'}. It guards the market alert parameter normalization entry point before any type-specific parsing.","triggerScenarios":"Creating/updating a market alert whose alert_type is anything other than 'market_light_status' or 'market_score_drop'-family values — e.g. 'market_light', 'price_drop', typo'd strings, or a portfolio alert type passed to the market API.","commonSituations":"API clients sending outdated or renamed alert type strings after an upgrade, confusing portfolio alert types (portfolio_stop_loss etc.) with market alert types, or frontend enums drifting from backend constants.","solutions":["Check the exact string being sent and compare with MARKET_ALERT_TYPES in src/services/market_light_alerts.py:21","Use 'market_light_status' (red/yellow light changes) or 'market_light_score_drop' (score drop threshold) as the alert_type","If a portfolio-style alert was intended, call the portfolio alert normalization (normalize_portfolio_alert_parameters) instead","Sync frontend/API-client enums with the backend frozenset to prevent drift"],"exampleFix":"# before\nnormalize_market_alert_parameters(\"market_status\", {\"statuses\": [\"red\"]})\n\n# after\nnormalize_market_alert_parameters(\"market_light_status\", {\"statuses\": [\"red\"]})","handlingStrategy":"type-guard","validationCode":"from src.services.market_light_alerts import MARKET_ALERT_TYPES\n\nif alert_type not in MARKET_ALERT_TYPES:\n    raise ValueError(f\"choose from {sorted(MARKET_ALERT_TYPES)}\")","typeGuard":"from src.services.market_light_alerts import MARKET_ALERT_TYPES\n\ndef is_valid_market_alert_type(alert_type: str) -> bool:\n    return isinstance(alert_type, str) and alert_type in MARKET_ALERT_TYPES","tryCatchPattern":"try:\n    params = normalize_market_alert_parameters(alert_type, parameters)\nexcept ValueError as exc:\n    if \"unsupported market alert_type\" in str(exc):\n        return api_error(400, str(exc))","preventionTips":["Drive frontend dropdowns from MARKET_ALERT_TYPES instead of hardcoding","Import the frozenset constant rather than duplicating the list client-side","Return 400 with the message so callers see the allowed values"],"tags":["validation","alerts","market-data","api-contract"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}