HKUDS/Vibe-Trading · error · ValueError
legs must be a non-empty array
Error message
legs must be a non-empty array
What it means
Thrown by _coerce_legs when the `legs` argument to the options payoff tool is not a JSON array or is an empty array. Legs define the option positions for payoff/greeks computation, so at least one leg is structurally required. This is the first schema gate before per-leg validation runs.
Source
Thrown at agent/src/tools/options_payoff_tool.py:231
},
"scenario_grid": {
"iv_values": _rounded_array(iv_values),
"spot": _rounded_array(report.spot_grid),
"pnl": [_rounded_array(row) for row in np.asarray(scenarios, dtype=float)],
},
"limitations": [
"European Black-Scholes marks with constant rate and volatility per scenario.",
"No dividends, early exercise, assignment, slippage, or margin model.",
"Scenario P&L is mark-to-market and does not deduct a hypothetical exit commission.",
],
}
return json.dumps(payload, ensure_ascii=False, allow_nan=False)
def _coerce_legs(raw: Any) -> list[OptionLeg]:
"""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")View on GitHub (pinned to 80ffdda44c)
Solutions
- Pass legs as a parsed JSON array with at least one leg object, e.g. [{"option_type":"call","strike":100,"qty":1}]
- If legs arrives as a JSON string, json.loads it before calling the tool
- Reject empty portfolios upstream in the calling agent's prompt/schema
Example fix
// before
result = execute({"legs": [], "entry_spot": 100})
// after
result = execute({"legs": [{"option_type": "call", "strike": 100, "qty": 1, "premium": 2.5}], "entry_spot": 100}) Defensive patterns
Strategy: validation
Validate before calling
import json
if isinstance(legs, str):
legs = json.loads(legs)
if not isinstance(legs, list) or not legs:
raise ValueError("legs must be a non-empty array of leg objects") Type guard
def is_legs_input(raw) -> bool:
return isinstance(raw, list) and len(raw) > 0 and all(isinstance(x, dict) for x in raw) Try / catch
try:
result = tool.execute(kwargs)
except ValueError as e:
return {"error": str(e)} # surface message to caller/LLM for self-correction Prevention
- Define a strict JSON schema (type: array, minItems: 1) in the tool description
- Parse JSON strings before forwarding
- Reject empty portfolios at the UI/agent layer
When it happens
Trigger: Calling execute or _portfolio_greeks with legs=None, legs="...", legs={} (a dict instead of list), or legs=[]. Often happens when the LLM/caller passes a JSON string instead of a parsed array, or omits legs entirely.
Common situations: Agent tool invocations where JSON arguments arrive as strings; clients building legs from user input that can be empty; passing an object keyed by leg index instead of an array.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- audit must be a list
- audit rows must be objects
- legs[{index}] must be an object
- invalid alpha_id
- alpha_id not found
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/249104e637225e52.
Report an issue: GitHub.