OpenBB-finance/OpenBB · error · OpenBBError
Error: underlying_price must be provided if underlying_price
Error message
Error: underlying_price must be provided if underlying_price is not available
What it means
Raised in OptionsChainsData._get_nearest_otm_strikes (options_chains_properties.py:552). The ITM/OTM boundary calculation needs the underlying spot price; it errors when underlying_price was not passed as an argument AND the DataFrame lacks an 'underlying_price' column (the hasattr check on a DataFrame is effectively a column-membership test). Same family as error 47 but on the moneyness helper path.
Source
Thrown at openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py:552
"""
# pylint: disable=import-outside-toplevel
from pandas import Series
if moneyness is None:
moneyness = 0.25
if 0 < moneyness < 100:
moneyness = moneyness / 100
if moneyness > 100 or moneyness < 0:
raise OpenBBError(
"Error: Moneyness must be expressed as a percentage between 0 and 100"
)
df = self.dataframe
if underlying_price is None and not hasattr(df, "underlying_price"):
raise OpenBBError(
"Error: underlying_price must be provided if underlying_price is not available"
)
if date is not None:
date = self._get_nearest_expiration(date)
df = df[df.expiration.astype(str) == date]
strikes = Series(df.strike.unique().tolist())
last_price = (
underlying_price
if underlying_price is not None
else df.underlying_price.iloc[0]
)
strikes = Series(self.strikes)
upper = last_price * (1 + moneyness) # type: ignore
lower = last_price * (1 - moneyness) # type: ignore
nearest_call = (upper - strikes).abs().idxmin()View on GitHub (pinned to 3e071fcc2c)
Solutions
- Set result.last_price = <spot> before calling moneyness-based filters (this injects the underlying_price column into the dataframe)
- Or pass underlying_price explicitly to the method that accepts it
- Or fetch from a provider that includes underlying_price in the chains payload
Example fix
# before df = res.filter_data(moneyness=25) # OpenBBError: underlying_price must be provided... # after res.last_price = 585.20 df = res.filter_data(moneyness=25)
Defensive patterns
Strategy: validation
Validate before calling
if "underlying_price" not in res.dataframe.columns and res.last_price is None:
if spot is None:
raise ValueError("need spot price for moneyness filtering")
res.last_price = spot
df = res.filter_data(moneyness=25) Type guard
def has_spot_for_moneyness(res) -> bool:
return "underlying_price" in res.to_df().columns or res.last_price is not None Try / catch
from openbb_core.app.model.abstract.error import OpenBBError
try:
df = res.filter_data(moneyness=25)
except OpenBBError as e:
if "underlying_price must be provided" in str(e):
res.last_price = get_spot(symbol)
df = res.filter_data(moneyness=25)
else:
raise Prevention
- Set last_price immediately after fetching chains from spot-free providers
- Keep a cached quote source next to your chains fetch
- Centralize a 'prepare chains result' helper that ensures the spot is present before any analytics
When it happens
Trigger: Calling filter_data(moneyness=25) (or any consumer of _get_nearest_otm_strikes) on a chains result whose provider omitted underlying_price, without supplying underlying_price explicitly and without setting result.last_price beforehand.
Common situations: Greeks/quotes-free providers that return only contract rows; processing saved/cached chains JSON where the spot field was dropped.
Related errors
- 'underlying_price' was not returned in the provider data.
- Error: '{stat}' could not be generated because the underlyin
- Error: Moneyness must be expressed as a percentage between 0
- Error: No validated data was found.
- Greeks are not available.
AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14).
Data as JSON: /api/errors/cc9a62ab00255674.
Report an issue: GitHub.