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

  1. Set result.last_price = <spot> before calling moneyness-based filters (this injects the underlying_price column into the dataframe)
  2. Or pass underlying_price explicitly to the method that accepts it
  3. 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

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


AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14). Data as JSON: /api/errors/cc9a62ab00255674. Report an issue: GitHub.