{"record":{"id":"6043ae843ce681e0","repo":"ZhuLinsen/daily_stock_analysis","slug":"invalid-price-rule-get-price","errorCode":null,"errorMessage":"invalid price: {rule.get('price')}","messagePattern":"invalid price: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agent/events.py","lineNumber":501,"sourceCode":"            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\n    if alert_type == AlertType.PRICE_CROSS:\n        direction = str(rule.get(\"direction\", \"above\")).lower()\n        if direction not in {\"above\", \"below\"}:\n            raise ValueError(f\"invalid direction: {direction}\")\n        try:\n            price = float(rule.get(\"price\"))\n        except (TypeError, ValueError) as exc:\n            raise ValueError(f\"invalid price: {rule.get('price')}\") from exc\n        if price <= 0:\n            raise ValueError(\"price must be > 0\")\n    elif alert_type == AlertType.PRICE_CHANGE_PERCENT:\n        direction = str(rule.get(\"direction\", \"up\")).lower()\n        if direction not in {\"up\", \"down\"}:\n            raise ValueError(f\"invalid direction: {direction}\")\n        try:\n            change_pct = float(rule.get(\"change_pct\"))\n        except (TypeError, ValueError) as exc:\n            raise ValueError(f\"invalid change_pct: {rule.get('change_pct')}\") from exc\n        if change_pct <= 0:\n            raise ValueError(\"change_pct must be > 0\")\n    elif alert_type == AlertType.VOLUME_SPIKE:\n        try:\n            multiplier = float(rule.get(\"multiplier\", 2.0))\n        except (TypeError, ValueError) as exc:\n            raise ValueError(f\"invalid multiplier: {rule.get('multiplier')}\") from exc\n        if multiplier <= 0:","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/agent/events.py#L483-L519","documentation":"Raised for PRICE_CROSS rules when the required 'price' field cannot be converted to float (TypeError when the key is missing — float(None) — or the value is a list/dict; ValueError for strings like '1,800' or 'N/A'). Unlike direction, price has NO default, so omitting it is itself an error.","triggerScenarios":"validate_event_alert_rule with alert_type='price_cross' and price absent, None, '1800.5.1', '1,800', or [1800]. Plain numeric strings like '1800.0' are accepted.","commonSituations":"Locale-formatted numbers with thousands separators or currency symbols from LLM output or scraped text; rule templates that forgot to fill the price; a None placeholder from an optional form field passed through unchecked.","solutions":["Include a plain numeric 'price' value (number or simple numeric string) in every price_cross rule.","Strip currency symbols and thousands separators, then parse, before constructing the rule from free-form text.","Treat a missing price on a price_cross rule as a hard schema error at the extraction/prompt layer, not at validation."],"exampleFix":"// before\nrule = {\"stock_code\": \"600519\", \"alert_type\": \"price_cross\", \"direction\": \"above\", \"price\": \"1,800\"}\n# ValueError: invalid price: 1,800\n\n// after\nrule = {\"stock_code\": \"600519\", \"alert_type\": \"price_cross\", \"direction\": \"above\", \"price\": 1800.0}\nvalidate_event_alert_rule(rule)","handlingStrategy":"validation","validationCode":"def parse_price(raw):\n    try:\n        return float(raw)\n    except (TypeError, ValueError):\n        cleaned = str(raw).replace(\",\", \"\").replace(\"$\", \"\").strip()\n        try:\n            return float(cleaned)\n        except (TypeError, ValueError):\n            return None","typeGuard":"def has_parseable_price(rule: dict) -> bool:\n    return parse_price(rule.get(\"price\")) is not None","tryCatchPattern":"try:\n    validate_event_alert_rule(rule)\nexcept ValueError as e:\n    if str(e).startswith(\"invalid price\"):\n        p = parse_price(rule.get(\"price\"))\n        if p is not None:\n            rule[\"price\"] = p\n            validate_event_alert_rule(rule)\n        else:\n            raise","preventionTips":["price is required for price_cross rules — no default exists.","Strip currency symbols and thousands separators before building rules from text.","In LLM extraction prompts, demand a plain decimal number for price."],"tags":["validation","event-monitor","price","type-coercion"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}