{"record":{"id":"73631477c318843d","repo":"OpenBB-finance/OpenBB","slug":"last-price-must-be-provided-for-options-filtering","errorCode":null,"errorMessage":"Last price must be provided for options filtering, and was not found in the data.","messagePattern":"Last price must be provided for options filtering, and was not found in the data\\.","errorType":"exception","errorClass":"OpenBBError","httpStatus":null,"severity":"error","filePath":"openbb_platform/extensions/derivatives/openbb_derivatives/options/options_router.py","lineNumber":166,"sourceCode":"\n    if isinstance(data, OptionsChainsData):\n        df = data.dataframe\n    elif isinstance(data, DataFrame):\n        df = data\n    elif isinstance(data, dict) and all(isinstance(v, list) for v in data.values()):\n        df = DataFrame(data)\n    elif isinstance(data, list):\n        if all(isinstance(d, dict) for d in data):\n            df = DataFrame(data)\n        elif all(isinstance(d, Data) for d in data):\n            df = DataFrame([d.model_dump(exclude_none=True, exclude_unset=True) for d in data])  # type: ignore\n\n    options = DataFrame(df.copy())\n\n    last_price = underlying_price or options.underlying_price.iloc[0]  # type: ignore\n\n    if last_price is None:\n        raise OpenBBError(\n            ValueError(\n                \"Last price must be provided for options filtering, and was not found in the data.\"\n            )\n        )\n\n    if target not in options.columns:  # type: ignore\n        raise OpenBBError(f\"Error: No {target} field found.\")\n    if \"dte\" not in options.columns:  # type: ignore\n        options.dte = (options.expiration - datetime.today().date()).days  # type: ignore\n\n    calls = options.query(f\"`option_type` == 'call' and `dte` >= 0 and `{target}` > 0\")  # type: ignore\n    puts = options.query(f\"`option_type` == 'put' and `dte` >= 0 and `{target}` > 0\")  # type: ignore\n\n    if oi:\n        calls = calls[calls[\"open_interest\"] > 0]\n        puts = puts[puts[\"open_interest\"] > 0]\n\n    if volume:","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/extensions/derivatives/openbb_derivatives/options/options_router.py#L148-L184","documentation":"Raised by the options processing/filtering helper when the resolved last_price is None. The value comes from 'underlying_price or options.underlying_price.iloc[0]' - so it fires when no underlying_price argument was passed AND the first row of the DataFrame's underlying_price column is None. Moneyness filtering needs the spot, so it aborts.","triggerScenarios":"Calling the options filter/processing helper with moneyness filtering on data where the underlying_price column exists but its first value is None (dumped with exclude_none semantics), and no underlying_price argument supplied. Note NaN passes this check (NaN is not None) and fails differently downstream.","commonSituations":"Providers that include the underlying_price field but leave it None on some rows; historical/EOD payloads missing the spot; user-constructed DataFrames where the column was added but never filled.","solutions":["Pass underlying_price explicitly to the call.","Backfill the column before processing: df['underlying_price'] = df['underlying_price'].ffill().bfill().fillna(spot).","Use a provider/date combination that returns a populated underlying_price.","Pre-validate: v = df.get('underlying_price'); require v is not None and not pd.isna(v.iloc[0])."],"exampleFix":"# before\nres = process_options(data=df, moneyness=5)  # underlying_price.iloc[0] is None\n\n# after\nres = process_options(data=df, moneyness=5, underlying_price=spot)","handlingStrategy":"validation","validationCode":"import pandas as pd\ncol = df.get('underlying_price')\nif underlying_price is None:\n    if col is None or col.empty or col.iloc[0] is None or pd.isna(col.iloc[0]):\n        raise ValueError('underlying_price unavailable; pass it explicitly')","typeGuard":"def has_spot(df, underlying_price=None) -> bool:\n    import pandas as pd\n    if underlying_price:\n        return True\n    col = df.get('underlying_price')\n    return col is not None and not col.empty and col.iloc[0] is not None and not pd.isna(col.iloc[0])","tryCatchPattern":"try:\n    res = process_options(data=df, moneyness=5)\nexcept OpenBBError as e:\n    if 'Last price must be provided' in str(e):\n        res = process_options(data=df, moneyness=5, underlying_price=get_spot(symbol))","preventionTips":["Pass underlying_price explicitly whenever moneyness filtering is requested.","Backfill/fill the underlying_price column at ingestion time.","Note NaN spot values pass the None check but poison downstream math - scrub both None and NaN."],"tags":["openbb","options","missing-argument","data-quality"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}