ZhuLinsen/daily_stock_analysis · error · ValueError

{field_name} must be a finite positive number

Error message

{field_name} must be a finite positive number

What it means

ValueError from DecisionSignalService._optional_price_float (src/services/decision_signal_service.py:1255): price fields (entry_low, entry_high, target prices) must be finite and strictly positive after float coercion. Rejects NaN, ±inf (math.isfinite check), zero, and negatives. NaN is notable because float('nan') succeeds in _optional_float but dies here.

Source

Thrown at src/services/decision_signal_service.py:1255

        text = sanitize_decision_signal_text(value)
        return text or None

    @staticmethod
    def _optional_float(value: Any, field_name: str) -> Optional[float]:
        if value in (None, ""):
            return None
        try:
            return float(value)
        except (TypeError, ValueError) as exc:
            raise ValueError(f"{field_name} must be a number") from exc

    @classmethod
    def _optional_price_float(cls, value: Any, field_name: str) -> Optional[float]:
        number = cls._optional_float(value, field_name)
        if number is None:
            return None
        if not math.isfinite(number) or number <= 0:
            raise ValueError(f"{field_name} must be a finite positive number")
        return number

    @staticmethod
    def _validate_entry_range(fields: Dict[str, Any]) -> None:
        entry_low = fields.get("entry_low")
        entry_high = fields.get("entry_high")
        if entry_low is not None and entry_high is not None and entry_low > entry_high:
            raise ValueError("entry_low must be less than or equal to entry_high")

    @staticmethod
    def _optional_int(value: Any, field_name: str) -> Optional[int]:
        if value in (None, ""):
            return None
        try:
            return int(value)
        except (TypeError, ValueError) as exc:
            raise ValueError(f"{field_name} must be an integer") from exc

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Drop non-finite/non-positive prices before the call: convert NaN/inf/<=0 to None and omit the field.
  2. Fix the upstream computation: guard divisions, use result if pd.notna(result) and result > 0 else None.
  3. Replace 0/-1 sentinel conventions with explicit nulls at the ingestion boundary.
  4. If a genuine zero price is legitimate in your domain, that is not supported — raise it with maintainers rather than bypassing.

Example fix

# before
entry_low = float(df['low'].iloc[0])  # may be NaN → ValueError
service.create_signal({..., "entry_low": entry_low})

# after
import math
raw_low = df['low'].iloc[0]
entry_low = float(raw_low) if raw_low is not None and math.isfinite(float(raw_low)) and float(raw_low) > 0 else None
service.create_signal({..., "entry_low": entry_low})
Defensive patterns

Strategy: validation

Validate before calling

import math
def as_price(v):
    if v in (None, ''):
        return None
    try:
        n = float(v)
    except (TypeError, ValueError):
        return None
    return n if math.isfinite(n) and n > 0 else None
payload['entry_low'] = as_price(payload.get('entry_low'))
payload['entry_high'] = as_price(payload.get('entry_high'))

Type guard

def is_valid_price(v) -> bool:
    if v in (None, ''):
        return True
    try:
        n = float(v)
    except (TypeError, ValueError):
        return False
    return math.isfinite(n) and n > 0

Prevention

When it happens

Trigger: entry_low: 0 (placeholder for 'no data'), entry_low: -1, NaN values propagated from upstream pandas computations (ffill on empty series → NaN), infinity from division by zero in derived price math, or negative values from bad scraping.

Common situations: Missing-price sentinels of 0/-1 in flat files; pandas/polars pipelines letting NaN/inf leak into payload dicts; per-share prices corrupted by unit mix-ups (cents vs dollars producing negatives after adjustment); math like (a-b)/b with b=0 yielding inf.

Related errors


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