HKUDS/Vibe-Trading · error · ValueError

legs may contain at most {_MAX_LEGS} entries

Error message

legs may contain at most {_MAX_LEGS} entries

What it means

Thrown by _coerce_legs when the legs array exceeds _MAX_LEGS entries. The tool caps portfolio size to bound compute and output size for payoff/greeks calculation. It fires after the non-empty check, before per-leg parsing.

Source

Thrown at agent/src/tools/options_payoff_tool.py:233

                "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")
        try:
            premium = None if raw_premium is None else float(raw_premium)

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Split the portfolio into multiple calls, each within the limit
  2. Filter to only the significant legs (non-zero qty) before sending
  3. Check _MAX_LEGS at the top of options_payoff_tool.py and stay under it

Example fix

// before
legs = build_all_50_legs(positions)
result = execute({"legs": legs, ...})
// after
legs = build_all_50_legs(positions)
for chunk in [legs[i:i+_MAX_LEGS] for i in range(0, len(legs), _MAX_LEGS)]:
    result = execute({"legs": chunk, ...})
Defensive patterns

Strategy: validation

Validate before calling

from agent.src.tools.options_payoff_tool import _MAX_LEGS
if len(legs) > _MAX_LEGS:
    legs = legs[:_MAX_LEGS]  # or split into chunks

Type guard

def within_leg_limit(legs: list) -> bool:
    return 0 < len(legs) <= _MAX_LEGS

Try / catch

try:
    execute(kwargs)
except ValueError as e:
    if "at most" in str(e):
        results = [execute({**kwargs, "legs": c}) for c in chunks(legs, _MAX_LEGS)]

Prevention

When it happens

Trigger: Calling execute/_portfolio_greeks with more than _MAX_LEGS leg objects (e.g. programmatically generated spreads, iron condors plus hedges, or batch portfolios).

Common situations: Scripts that synthesize many strikes for a strategy sweep; users pasting a whole position file into the tool; LLMs generating oversized illustrative portfolios.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/c5ca413f0d928168. Report an issue: GitHub.