{"record":{"id":"4860bba086cd2579","repo":"HKUDS/Vibe-Trading","slug":"legs-index-must-be-an-object","errorCode":null,"errorMessage":"legs[{index}] must be an object","messagePattern":"legs\\[(.+?)\\] must be an object","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/options_payoff_tool.py","lineNumber":238,"sourceCode":"                \"European Black-Scholes marks with constant rate and volatility per scenario.\",\n                \"No dividends, early exercise, assignment, slippage, or margin model.\",\n                \"Scenario P&L is mark-to-market and does not deduct a hypothetical exit commission.\",\n            ],\n        }\n        return json.dumps(payload, ensure_ascii=False, allow_nan=False)\n\n\ndef _coerce_legs(raw: Any) -> list[OptionLeg]:\n    \"\"\"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","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/options_payoff_tool.py#L220-L256","documentation":"Thrown while iterating legs when an element is not a JSON object (dict). Each leg must be a mapping with option_type/strike/qty keys; a scalar, string, list, or null element triggers this with the offending index in the message.","triggerScenarios":"legs=[100, 200], legs=[\"call@100\"], legs=[[\"call\",100,1]], or legs=[null]. Typical when callers encode legs as compact tuples/strings instead of objects.","commonSituations":"LLM tool calls that compress legs into shorthand formats; CSV/TSV import code mapping rows to scalars; mixed malformed data from user-edited JSON.","solutions":["Make every element a dict: {\"option_type\": ..., \"strike\": ..., \"qty\": ...}","If data arrives as tuples, map them: legs=[{\"option_type\":t,\"strike\":s,\"qty\":q} for t,s,q in raw]","Validate the whole array shape client-side before invoking the tool"],"exampleFix":"// before\nexecute({\"legs\": [\"call\", 100, 1], ...})\n// after\nexecute({\"legs\": [{\"option_type\": \"call\", \"strike\": 100, \"qty\": 1}], ...})","handlingStrategy":"type-guard","validationCode":"bad = [i for i, x in enumerate(legs) if not isinstance(x, dict)]\nif bad:\n    raise ValueError(f\"legs entries not objects at indices {bad}\")","typeGuard":"def legs_all_objects(legs) -> bool:\n    return isinstance(legs, list) and all(isinstance(x, dict) for x in legs)","tryCatchPattern":"try:\n    execute(kwargs)\nexcept ValueError as e:\n    if \"must be an object\" in str(e):\n        fix_element(int(str(e).split('[')[1].split(']')[0]))","preventionTips":["Use a pydantic model per leg and parse with type enforcement","Never encode legs as tuples or strings","Validate array element types before tool dispatch"],"tags":["validation","options","json"],"backgroundTag":"schema-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}