ZhuLinsen/daily_stock_analysis · error · ValueError
{field_name} must be an integer
Error message
{field_name} must be an integer What it means
Raised by _int_in_range (src/services/alert_indicators.py:382): the value converted to int successfully, but its canonical string form does not equal str(number) or f'{number}.0', i.e. it is a non-integer-shaped value. This deliberately rejects inputs like "12.5", 3.7, or "1e2" that int() would otherwise truncate, preventing silently accepted-but-wrong periods.
Source
Thrown at src/services/alert_indicators.py:382
)
return params
def _direction(value: Any, allowed: frozenset[str], *, default: str) -> str:
direction = str(value or default).strip().lower()
if direction not in allowed:
raise ValueError(f"invalid direction: {direction}")
return direction
def _int_in_range(value: Any, field_name: str, *, default: int, minimum: int = 2, maximum: int = 250) -> int:
raw_value = default if value is None or value == "" else value
try:
number = int(raw_value)
except (TypeError, ValueError) as exc:
raise ValueError(f"invalid {field_name}: {value}") from exc
if str(raw_value).strip() not in {str(number), f"{number}.0"}:
raise ValueError(f"{field_name} must be an integer")
if number < minimum or number > maximum:
raise ValueError(f"{field_name} must be between {minimum} and {maximum}")
return number
def _finite_float(value: Any, field_name: str) -> float:
try:
number = float(value)
except (TypeError, ValueError) as exc:
raise ValueError(f"invalid {field_name}: {value}") from exc
if not isfinite(number):
raise ValueError(f"{field_name} must be finite")
return number
def _float_in_range(
value: Any,
field_name: str,View on GitHub (pinned to 5159bd72e8)
Solutions
- Round or floor the value deliberately on the client before submitting: Math.round(value).
- Use a stepper input with step=1 for period fields.
- If a decimal period ever seems meaningful, the indicator does not support it — pick an integer design instead.
Example fix
// before
{ "alert_type": "ma_price_cross", "parameters": { "window": 20.5 } }
// after
{ "alert_type": "ma_price_cross", "parameters": { "window": Math.round(20.5) /* 21 */ } } Defensive patterns
Strategy: validation
Validate before calling
def to_int_field(v):
if v is None or v == '':
return None # default
f = float(v)
if f != int(f):
raise ValueError('fractional period not allowed')
return int(f)
params = {k: (to_int_field(v) if k in INT_FIELDS else v) for k, v in params.items()} Type guard
def is_integer_shaped(v) -> bool:
if v is None or v == '':
return True
try:
s = str(v).strip(); n = int(v)
except (TypeError, ValueError):
return False
return s in {str(n), f'{n}.0'} Try / catch
try:
normalize_indicator_parameters(alert_type, params)
except ValueError as e:
if 'must be an integer' in str(e):
for k in INT_FIELDS & params.keys():
params[k] = int(float(params[k])) if str(params[k]).replace('.','',1).isdigit() else params[k]
normalize_indicator_parameters(alert_type, params)
else:
raise Prevention
- Round deliberately (Math.round) before submit instead of relying on server truncation — the server refuses truncation.
- Use step=1 steppers in forms for period fields.
- Watch for unit conversions that produce fractional periods.
When it happens
Trigger: parameters like {"window": 20.5}, {"period": "9.25"}, {"fast_period": 12.5}. Accepted shapes are exact ints (20), int strings ("20"), and float-with-.0 (20.0, "20.0") — because int(20.9) is 20, the guard catches the fractional part.
Common situations: Sliders or step-less inputs emitting fractional values; unit conversion producing decimals (e.g. 26 * 0.5); spreadsheets storing numbers as decimals ("12,0" in EU locale parses oddly).
Related errors
- invalid {field_name}: {value}
- {field_name} must be between {minimum} and {maximum}
- {field_name} must be finite
- unsupported alert_type for current EventMonitor runtime: {al
- Event alert rules must be a JSON array
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/29992bfa09cc1684.
Report an issue: GitHub.