HKUDS/Vibe-Trading · error · ValueError
legs[{index}].qty must be a non-zero integer
Error message
legs[{index}].qty must be a non-zero integer What it means
Thrown when qty converts to float but is not a usable whole-number quantity: either it's a Python bool (True/False pass float() as 1.0/0.0) or it has a fractional part. Options trade in integer contract counts, so qty must be a non-zero integer value.
Source
Thrown at agent/src/tools/options_payoff_tool.py:247
"""Parse and validate raw JSON-style leg objects."""
if not isinstance(raw, list) or not raw:
raise ValueError("legs must be a non-empty array")
if len(raw) > _MAX_LEGS:
raise ValueError(f"legs may contain at most {_MAX_LEGS} entries")
legs: list[OptionLeg] = []
for index, item in enumerate(raw):
if not isinstance(item, dict):
raise ValueError(f"legs[{index}] must be an object")
option_type = str(item.get("option_type") or "").strip().lower()
try:
strike = float(item["strike"])
raw_qty = item["qty"]
qty_number = float(raw_qty)
except (KeyError, TypeError, ValueError, OverflowError) as exc:
raise ValueError(f"legs[{index}] has invalid strike or qty: {exc}") from exc
if isinstance(raw_qty, bool) or not qty_number.is_integer():
raise ValueError(f"legs[{index}].qty must be a non-zero integer")
qty = int(qty_number)
raw_premium = item.get("premium")
try:
premium = None if raw_premium is None else float(raw_premium)
except (TypeError, ValueError, OverflowError) as exc:
raise ValueError(f"legs[{index}].premium must be numeric or null") from exc
legs.append(OptionLeg(option_type, strike, qty, premium))
return legs
def _required_float(kwargs: dict[str, Any], name: str) -> float:
"""Read a required finite float."""
if name not in kwargs or kwargs[name] is None or kwargs[name] == "":
raise ValueError(f"{name} is required")
try:
value = float(kwargs[name])
except (TypeError, ValueError, OverflowError) as exc:
raise ValueError(f"{name} must be numeric") from excView on GitHub (pinned to 80ffdda44c)
Solutions
- Round or reject fractional quantities before sending: qty=int(round(x)) only when semantically valid
- Never send booleans as qty
- Express ratios via separate legs with integer quantities or premium adjustments
Example fix
// before
{"option_type": "call", "strike": 100, "qty": 2.5}
// after
{"option_type": "call", "strike": 100, "qty": 3} // round to whole contracts Defensive patterns
Strategy: validation
Validate before calling
import math
for leg in legs:
q = float(leg["qty"])
assert not isinstance(leg["qty"], bool) and q.is_integer() and q != 0, leg Type guard
def qty_is_valid(raw) -> bool:
if isinstance(raw, bool): return False
try: v = float(raw)
except (TypeError, ValueError, OverflowError): return False
return v.is_integer() and v != 0 Try / catch
try:
execute(kwargs)
except ValueError as e:
if "non-zero integer" in str(e):
leg['qty'] = int(round(float(leg['qty']))) # retry once if rounding acceptable Prevention
- Use integer input fields in UIs for contract counts
- Reject boolean-typed quantities in your schema
- Never port fractional-share logic to options
When it happens
Trigger: qty=2.5, qty=0.5, qty=True, or qty=0-adjacent fractional values. Note float NaN also fails is_integer(). The message says non-zero, so qty=0.0 would also be rejected here.
Common situations: Position sizing calculators emitting fractional contracts; JSON auto-coercion of booleans; partial-share style APIs reused for options; users expressing ratio-weighted spreads.
Related errors
- T must be > 0 to imply a volatility, got {T}
- legs must be a non-empty array
- legs may contain at most {_MAX_LEGS} entries
- legs[{index}] must be an object
- legs[{index}] has invalid strike or qty: {exc}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/5db961f49f95d012.
Report an issue: GitHub.