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
- Drop non-finite/non-positive prices before the call: convert NaN/inf/<=0 to None and omit the field.
- Fix the upstream computation: guard divisions, use result if pd.notna(result) and result > 0 else None.
- Replace 0/-1 sentinel conventions with explicit nulls at the ingestion boundary.
- 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
- Filter NaN/inf/<=0 out of pandas-derived prices before building payloads.
- Guard upstream divisions that can yield inf; use pd.notna checks.
- Replace 0/-1 'missing price' sentinels with explicit nulls at the edge.
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
- entry_low must be less than or equal to entry_high
- score must be between 0 and 100
- 配置校验失败
- invalid price: {rule.get('price')}
- price must be > 0
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/82276a3c71cd2f37.
Report an issue: GitHub.