HKUDS/Vibe-Trading · error · ValueError

legs[{index}].premium must be numeric or null

Error message

legs[{index}].premium must be numeric or null

What it means

Thrown when a leg's optional premium field is present but cannot be converted to float (string garbage, list, dict, bool-adjacent overflow). premium may be null/omitted to let the tool default it, but any present value must be numeric.

Source

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

    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 exc
    if not math.isfinite(value):
        raise ValueError(f"{name} must be finite")
    return value


def _optional_float(kwargs: dict[str, Any], name: str, default: float) -> float:

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Coerce premium to a plain number or set it to null
  2. Parse broker text: float(re.sub(r'[^0-9.\-]', '', raw)) with a guard
  3. Omit the premium key entirely when unknown

Example fix

// before
{"option_type": "call", "strike": 100, "qty": 1, "premium": "2.50 x"}
// after
{"option_type": "call", "strike": 100, "qty": 1, "premium": 2.50}
Defensive patterns

Strategy: validation

Validate before calling

for leg in legs:
    p = leg.get("premium")
    if p is not None:
        try: float(p)
        except (TypeError, ValueError, OverflowError): leg["premium"] = None  # or hard-fail

Type guard

def premium_ok(leg: dict) -> bool:
    p = leg.get("premium")
    if p is None: return True
    try: float(p); return True
    except (TypeError, ValueError, OverflowError): return False

Try / catch

try:
    execute(kwargs)
except ValueError as e:
    if "premium must be numeric" in str(e):
        strip_premiums_and_retry(kwargs)

Prevention

When it happens

Trigger: premium="2.5bp", premium=[2.5], premium={"value":2.5}, premium=float('inf') from parsed JSON 'Infinity'.

Common situations: Premiums imported from broker CSVs with text like '2.50 x' or '—'; LLM hallucinating structured premium objects; spreadsheets returning strings.

Related errors


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