ZhuLinsen/daily_stock_analysis · error · ValueError

price must be > 0

Error message

price must be > 0

What it means

Raised for PRICE_CROSS rules when 'price' parses as a float but is <= 0. A zero or negative threshold is meaningless for a stock price cross, so validation rejects it before the rule can enter the monitor and never trigger (or always mis-trigger).

Source

Thrown at src/agent/events.py:503

    ttl_hours = rule.get("ttl_hours")
    if ttl_hours is not None:
        try:
            ttl_value = float(ttl_hours)
        except (TypeError, ValueError) as exc:
            raise ValueError(f"invalid ttl_hours: {ttl_hours}") from exc
        if ttl_value <= 0:
            raise ValueError("ttl_hours must be > 0")

    if alert_type == AlertType.PRICE_CROSS:
        direction = str(rule.get("direction", "above")).lower()
        if direction not in {"above", "below"}:
            raise ValueError(f"invalid direction: {direction}")
        try:
            price = float(rule.get("price"))
        except (TypeError, ValueError) as exc:
            raise ValueError(f"invalid price: {rule.get('price')}") from exc
        if price <= 0:
            raise ValueError("price must be > 0")
    elif alert_type == AlertType.PRICE_CHANGE_PERCENT:
        direction = str(rule.get("direction", "up")).lower()
        if direction not in {"up", "down"}:
            raise ValueError(f"invalid direction: {direction}")
        try:
            change_pct = float(rule.get("change_pct"))
        except (TypeError, ValueError) as exc:
            raise ValueError(f"invalid change_pct: {rule.get('change_pct')}") from exc
        if change_pct <= 0:
            raise ValueError("change_pct must be > 0")
    elif alert_type == AlertType.VOLUME_SPIKE:
        try:
            multiplier = float(rule.get("multiplier", 2.0))
        except (TypeError, ValueError) as exc:
            raise ValueError(f"invalid multiplier: {rule.get('multiplier')}") from exc
        if multiplier <= 0:
            raise ValueError("multiplier must be > 0")

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Set price to the positive absolute price threshold you want (e.g. 1800.0).
  2. If you meant a percentage move, use alert_type='price_change_percent' with change_pct instead of price.
  3. Validate extracted prices at the LLM-parsing layer: reject 0/negative placeholders and re-ask or fall back to the current quote.

Example fix

// before
rule = {"stock_code": "600519", "alert_type": "price_cross", "direction": "above", "price": 0}
# ValueError: price must be > 0

// after
rule = {"stock_code": "600519", "alert_type": "price_cross", "direction": "above", "price": 1800.0}
validate_event_alert_rule(rule)
Defensive patterns

Strategy: validation

Validate before calling

def positive_price(raw) -> bool:
    try:
        return float(raw) > 0
    except (TypeError, ValueError):
        return False

Type guard

def has_positive_price(rule: dict) -> bool:
    return positive_price(rule.get("price"))

Try / catch

try:
    validate_event_alert_rule(rule)
except ValueError as e:
    if "price must be" in str(e):
        reject(rule, "price threshold must be a positive absolute price")

Prevention

When it happens

Trigger: validate_event_alert_rule with alert_type='price_cross' and price = 0, -50, 0.0, or '0'. Also reachable when unparsed text coerces unexpectedly (e.g. float of a string like '0').

Common situations: Unset numeric UI field defaulting to 0; an LLM emitting 0 as a placeholder for 'current price'; negative values from buggy delta/threshold arithmetic being reused as absolute price; sentinel -1 reused from a different config schema.

Related errors


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