{"record":{"id":"5936dd03712c059a","repo":"HKUDS/Vibe-Trading","slug":"name-must-be-finite","errorCode":null,"errorMessage":"{name} must be finite","messagePattern":"(.+?) must be finite","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/options_payoff_tool.py","lineNumber":267,"sourceCode":"        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\n    if not math.isfinite(value):\n        raise ValueError(f\"{name} must be finite\")\n    return value\n\n\ndef _optional_float(kwargs: dict[str, Any], name: str, default: float) -> float:\n    \"\"\"Read an optional finite float, treating null and empty text as omitted.\"\"\"\n    raw = kwargs.get(name)\n    if raw is None or raw == \"\":\n        return default\n    try:\n        value = float(raw)\n    except (TypeError, ValueError, OverflowError) as exc:\n        raise ValueError(f\"{name} must be numeric\") from exc\n    if not math.isfinite(value):\n        raise ValueError(f\"{name} must be finite\")\n    return value\n\n\ndef _spot_points(raw: Any) -> int:","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/options_payoff_tool.py#L249-L285","documentation":"Thrown by _required_float when a required parameter converts to float but is NaN or ±Infinity (math.isfinite fails). JSON cannot legally carry these, but Python float('nan'), parsed 'NaN' strings, or division artifacts can reach the tool. Payoff math over infinite spots is meaningless, so it's rejected.","triggerScenarios":"entry_spot=float('nan') from a failed upstream computation; parsing 'Infinity' via json.loads with default settings; 0/0 ratios forwarded as volatility input.","commonSituations":"Data pipelines where upstream math produced NaN silently; permissive JSON parsers accepting NaN/Infinity literals; missing data encoded as NaN instead of null.","solutions":["Check math.isfinite upstream and substitute a real value or abort with a clear error","Avoid json.dumps(..., allow_nan=True) round-trips; use null for missing","Log which parameter was non-finite before calling the tool"],"exampleFix":"// before\nspot = compute_spot()  # may be nan\nexecute({\"legs\": legs, \"entry_spot\": spot})\n// after\nspot = compute_spot()\nif spot is None or not math.isfinite(spot):\n    raise ValueError(\"upstream spot missing\")\nexecute({\"legs\": legs, \"entry_spot\": spot})","handlingStrategy":"validation","validationCode":"import math\nfor k, v in kwargs.items():\n    if isinstance(v, float) and not math.isfinite(v):\n        raise ValueError(f\"{k} is not finite\")","typeGuard":"def all_numeric_kwargs_finite(kwargs: dict) -> bool:\n    return all(math.isfinite(v) for v in kwargs.values() if isinstance(v, float))","tryCatchPattern":"try:\n    execute(kwargs)\nexcept ValueError as e:\n    if \"must be finite\" in str(e):\n        substitute_or_refetch_parameter(e)","preventionTips":["Use json.dumps default (allow_nan=False) to catch NaN early","Treat missing data as None, never NaN","Assert finiteness after risky arithmetic upstream"],"tags":["validation","nan","options"],"backgroundTag":"non-finite-number","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}