{"record":{"id":"5db961f49f95d012","repo":"HKUDS/Vibe-Trading","slug":"legs-index-qty-must-be-a-non-zero-integer","errorCode":null,"errorMessage":"legs[{index}].qty must be a non-zero integer","messagePattern":"legs\\[(.+?)\\]\\.qty must be a non-zero integer","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/options_payoff_tool.py","lineNumber":247,"sourceCode":"    \"\"\"Parse and validate raw JSON-style leg objects.\"\"\"\n    if not isinstance(raw, list) or not raw:\n        raise ValueError(\"legs must be a non-empty array\")\n    if len(raw) > _MAX_LEGS:\n        raise ValueError(f\"legs may contain at most {_MAX_LEGS} entries\")\n\n    legs: list[OptionLeg] = []\n    for index, item in enumerate(raw):\n        if not isinstance(item, dict):\n            raise ValueError(f\"legs[{index}] must be an object\")\n        option_type = str(item.get(\"option_type\") or \"\").strip().lower()\n        try:\n            strike = float(item[\"strike\"])\n            raw_qty = item[\"qty\"]\n            qty_number = float(raw_qty)\n        except (KeyError, TypeError, ValueError, OverflowError) as exc:\n            raise ValueError(f\"legs[{index}] has invalid strike or qty: {exc}\") from exc\n        if isinstance(raw_qty, bool) or not qty_number.is_integer():\n            raise ValueError(f\"legs[{index}].qty must be a non-zero integer\")\n        qty = int(qty_number)\n        raw_premium = item.get(\"premium\")\n        try:\n            premium = None if raw_premium is None else float(raw_premium)\n        except (TypeError, ValueError, OverflowError) as exc:\n            raise ValueError(f\"legs[{index}].premium must be numeric or null\") from exc\n        legs.append(OptionLeg(option_type, strike, qty, premium))\n    return legs\n\n\ndef _required_float(kwargs: dict[str, Any], name: str) -> float:\n    \"\"\"Read a required finite float.\"\"\"\n    if name not in kwargs or kwargs[name] is None or kwargs[name] == \"\":\n        raise ValueError(f\"{name} is required\")\n    try:\n        value = float(kwargs[name])\n    except (TypeError, ValueError, OverflowError) as exc:\n        raise ValueError(f\"{name} must be numeric\") from exc","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/options_payoff_tool.py#L229-L265","documentation":"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.","triggerScenarios":"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.","commonSituations":"Position sizing calculators emitting fractional contracts; JSON auto-coercion of booleans; partial-share style APIs reused for options; users expressing ratio-weighted spreads.","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"],"exampleFix":"// before\n{\"option_type\": \"call\", \"strike\": 100, \"qty\": 2.5}\n// after\n{\"option_type\": \"call\", \"strike\": 100, \"qty\": 3}  // round to whole contracts","handlingStrategy":"validation","validationCode":"import math\nfor leg in legs:\n    q = float(leg[\"qty\"])\n    assert not isinstance(leg[\"qty\"], bool) and q.is_integer() and q != 0, leg","typeGuard":"def qty_is_valid(raw) -> bool:\n    if isinstance(raw, bool): return False\n    try: v = float(raw)\n    except (TypeError, ValueError, OverflowError): return False\n    return v.is_integer() and v != 0","tryCatchPattern":"try:\n    execute(kwargs)\nexcept ValueError as e:\n    if \"non-zero integer\" in str(e):\n        leg['qty'] = int(round(float(leg['qty'])))  # retry once if rounding acceptable","preventionTips":["Use integer input fields in UIs for contract counts","Reject boolean-typed quantities in your schema","Never port fractional-share logic to options"],"tags":["validation","options","integers"],"backgroundTag":"numeric-field-invalid","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}