{"record":{"id":"0c92a20c75681683","repo":"OpenBB-finance/OpenBB","slug":"underlying-price-was-not-returned-in-the-provide","errorCode":null,"errorMessage":"'underlying_price' was not returned in the provider data.\n\n Please set the 'last_price' property and try again.\n\n Note: This error does not impact the standard OBBject `to_df()` method.","messagePattern":"'underlying_price' was not returned in the provider data\\.\n\n Please set the 'last_price' property and try again\\.\n\n Note: This error does not impact the standard OBBject `to_df\\(\\)` method\\.","errorType":"exception","errorClass":"OpenBBError","httpStatus":null,"severity":"error","filePath":"openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py","lineNumber":62,"sourceCode":"\n    @cached_property\n    def dataframe(self) -> \"DataFrame\":\n        \"\"\"Return all data as a Pandas DataFrame,\n        with additional computed columns (Breakeven, GEX, DEX) if available.\n        \"\"\"\n        # pylint: disable=import-outside-toplevel\n        from numpy import nan\n        from pandas import DataFrame, DatetimeIndex, Timedelta, concat, to_datetime\n\n        chains_data = DataFrame(\n            self.model_dump(\n                exclude_unset=True,\n                exclude_none=True,\n            )\n        )\n\n        if \"underlying_price\" not in chains_data.columns and not self.last_price:\n            raise OpenBBError(\n                \"'underlying_price' was not returned in the provider data.\"\n                + \"\\n\\n Please set the 'last_price' property and try again.\"\n                + \"\\n\\n Note: This error does not impact the standard OBBject `to_df()` method.\"\n            )\n\n        # Add the underlying price to the DataFrame, or override the existing price.\n        if self.last_price:\n            chains_data[\"underlying_price\"] = self.last_price\n\n        if chains_data.empty:\n            raise OpenBBError(\"Error: No validated data was found.\")\n\n        if \"dte\" not in chains_data.columns and \"eod_date\" in chains_data.columns:\n            _date = to_datetime(chains_data.eod_date)\n            temp = DatetimeIndex(chains_data.expiration)\n            temp_ = temp - _date  # type: ignore\n            chains_data[\"dte\"] = [Timedelta(_temp_).days for _temp_ in temp_]\n","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py#L44-L80","documentation":"Raised by the cached OptionsChainsData.dataframe property (options_chains_properties.py). The property builds a DataFrame from the validated model dump; if the provider's data contained no 'underlying_price' column AND the user has not set the manual last_price override, exposure-based columns (DEX/GEX/breakeven) cannot be computed, so the property refuses to build. The plain OBBject.to_df() path is unaffected.","triggerScenarios":"Accessing result.dataframe (or any chained convenience like total_gex, straddle()) on an options chains result from a provider that does not return underlying_price, without first setting result.last_price = <price>. The check is skipped if last_price was set.","commonSituations":"Providers whose fetchers return only contract rows without the spot price; historical/delayed snapshots where the spot field is empty; users switching providers and hitting divergent field coverage.","solutions":["Set the manual override before touching .dataframe: result.last_price = 185.50","Or use a provider that returns underlying_price (e.g. tradier/yfinance derivatives endpoints)","If you only need the raw rows, use result.to_df() which bypasses this enriched property"],"exampleFix":"# before\nres = await obb.derivatives.options.chains(symbol=\"SPY\", provider=\"...\")\ndf = res.dataframe  # OpenBBError: 'underlying_price' was not returned\n\n# after\nres = await obb.derivatives.options.chains(symbol=\"SPY\", provider=\"...\")\nres.last_price = 585.20\ndf = res.dataframe","handlingStrategy":"validation","validationCode":"def ensure_underlying_price(res, fallback_price: float):\n    if \"underlying_price\" not in res.to_df().columns and res.last_price is None:\n        if fallback_price is None:\n            raise ValueError(\"need a spot price: provider returned none\")\n        res.last_price = fallback_price\n    return res","typeGuard":"def has_underlying_price(res) -> bool:\n    df = res.to_df()\n    return \"underlying_price\" in df.columns or res.last_price is not None","tryCatchPattern":"from openbb_core.provider.abstract.data import Data\nfrom openbb_core.app.model.abstract.error import OpenBBError\n\ntry:\n    df = res.dataframe\nexcept OpenBBError as e:\n    if \"underlying_price\" in str(e):\n        res.last_price = get_spot(symbol)  # fetch spot from a quotes endpoint\n        df = res.dataframe\n    else:\n        raise","preventionTips":["After fetching chains, immediately set result.last_price from your own quotes source if the provider omits it","Feature-detect provider coverage ('underlying_price' in to_df().columns) before using enriched properties","Remember to_df() always works; only the enriched .dataframe path needs the spot"],"tags":["options","dataframe","underlying-price","derivatives"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}