OpenBB-finance/OpenBB · error · OpenBBError

Last price must be provided for options filtering, and was…

Error message

Last price must be provided for options filtering, and was not found in the data.

What it means

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.

Solutions

  1. Pass underlying_price explicitly to the call.
  2. Backfill the column before processing: df['underlying_price'] = df['underlying_price'].ffill().bfill().fillna(spot).
  3. Use a provider/date combination that returns a populated underlying_price.
  4. Pre-validate: v = df.get('underlying_price'); require v is not None and not pd.isna(v.iloc[0]).

Example fix

# before
res = process_options(data=df, moneyness=5)  # underlying_price.iloc[0] is None

# after
res = process_options(data=df, moneyness=5, underlying_price=spot)
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd
col = df.get('underlying_price')
if underlying_price is None:
    if col is None or col.empty or col.iloc[0] is None or pd.isna(col.iloc[0]):
        raise ValueError('underlying_price unavailable; pass it explicitly')

Type guard

def has_spot(df, underlying_price=None) -> bool:
    import pandas as pd
    if underlying_price:
        return True
    col = df.get('underlying_price')
    return col is not None and not col.empty and col.iloc[0] is not None and not pd.isna(col.iloc[0])

Try / catch

try:
    res = process_options(data=df, moneyness=5)
except OpenBBError as e:
    if 'Last price must be provided' in str(e):
        res = process_options(data=df, moneyness=5, underlying_price=get_spot(symbol))

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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

Appendix: source

Thrown at openbb_platform/extensions/derivatives/openbb_derivatives/options/options_router.py:166

    if isinstance(data, OptionsChainsData):
        df = data.dataframe
    elif isinstance(data, DataFrame):
        df = data
    elif isinstance(data, dict) and all(isinstance(v, list) for v in data.values()):
        df = DataFrame(data)
    elif isinstance(data, list):
        if all(isinstance(d, dict) for d in data):
            df = DataFrame(data)
        elif all(isinstance(d, Data) for d in data):
            df = DataFrame([d.model_dump(exclude_none=True, exclude_unset=True) for d in data])  # type: ignore

    options = DataFrame(df.copy())

    last_price = underlying_price or options.underlying_price.iloc[0]  # type: ignore

    if last_price is None:
        raise OpenBBError(
            ValueError(
                "Last price must be provided for options filtering, and was not found in the data."
            )
        )

    if target not in options.columns:  # type: ignore
        raise OpenBBError(f"Error: No {target} field found.")
    if "dte" not in options.columns:  # type: ignore
        options.dte = (options.expiration - datetime.today().date()).days  # type: ignore

    calls = options.query(f"`option_type` == 'call' and `dte` >= 0 and `{target}` > 0")  # type: ignore
    puts = options.query(f"`option_type` == 'put' and `dte` >= 0 and `{target}` > 0")  # type: ignore

    if oi:
        calls = calls[calls["open_interest"] > 0]
        puts = puts[puts["open_interest"] > 0]

    if volume:

View on GitHub (pinned to 3e071fcc2c)