OpenBB-finance/OpenBB · error · OpenBBError
'underlying_price' was not returned in the provider data.
Error message
'underlying_price' was not returned in the provider data. Please set the 'last_price' property and try again. Note: This error does not impact the standard OBBject `to_df()` method.
What it means
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.
Source
Thrown at openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py:62
@cached_property
def dataframe(self) -> "DataFrame":
"""Return all data as a Pandas DataFrame,
with additional computed columns (Breakeven, GEX, DEX) if available.
"""
# pylint: disable=import-outside-toplevel
from numpy import nan
from pandas import DataFrame, DatetimeIndex, Timedelta, concat, to_datetime
chains_data = DataFrame(
self.model_dump(
exclude_unset=True,
exclude_none=True,
)
)
if "underlying_price" not in chains_data.columns and not self.last_price:
raise OpenBBError(
"'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."
)
# Add the underlying price to the DataFrame, or override the existing price.
if self.last_price:
chains_data["underlying_price"] = self.last_price
if chains_data.empty:
raise OpenBBError("Error: No validated data was found.")
if "dte" not in chains_data.columns and "eod_date" in chains_data.columns:
_date = to_datetime(chains_data.eod_date)
temp = DatetimeIndex(chains_data.expiration)
temp_ = temp - _date # type: ignore
chains_data["dte"] = [Timedelta(_temp_).days for _temp_ in temp_]
View on GitHub (pinned to 3e071fcc2c)
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
Example fix
# before res = await obb.derivatives.options.chains(symbol="SPY", provider="...") df = res.dataframe # OpenBBError: 'underlying_price' was not returned # after res = await obb.derivatives.options.chains(symbol="SPY", provider="...") res.last_price = 585.20 df = res.dataframe
Defensive patterns
Strategy: validation
Validate before calling
def ensure_underlying_price(res, fallback_price: float):
if "underlying_price" not in res.to_df().columns and res.last_price is None:
if fallback_price is None:
raise ValueError("need a spot price: provider returned none")
res.last_price = fallback_price
return res Type guard
def has_underlying_price(res) -> bool:
df = res.to_df()
return "underlying_price" in df.columns or res.last_price is not None Try / catch
from openbb_core.provider.abstract.data import Data
from openbb_core.app.model.abstract.error import OpenBBError
try:
df = res.dataframe
except OpenBBError as e:
if "underlying_price" in str(e):
res.last_price = get_spot(symbol) # fetch spot from a quotes endpoint
df = res.dataframe
else:
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Error: No validated data was found.
- Error: '{stat}' could not be generated because the underlyin
- Error: underlying_price must be provided if underlying_price
- Greeks are not available.
- Error: stat must be one of ['open_interest', 'volume', 'dex'
AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14).
Data as JSON: /api/errors/0c92a20c75681683.
Report an issue: GitHub.