OpenBB-finance/OpenBB · error · ValueError

Expected list of dicts, got dict

Error message

Expected list of dicts, got dict

What it means

Raised by openbb_fmp get_data_many when the FMP response, after optional sub_dict extraction, is still a dict instead of the list[dict] the fetcher expects. This is a shape mismatch: the endpoint returned a keyed object (or an error/limit payload) where a list of records was required.

Source

Thrown at openbb_platform/providers/fmp/openbb_fmp/utils/helpers.py:121

    Parameters
    ----------
    url: str
        The URL to get the data from.
    sub_dict: Optional[str]
        The sub-dictionary to use.

    Returns
    -------
    list[dict]
        Dictionary of data.
    """
    data = await get_data(url, **kwargs)

    if sub_dict and isinstance(data, dict):
        data = data.get(sub_dict, [])
    if isinstance(data, dict):
        raise ValueError("Expected list of dicts, got dict")
    if len(data) == 0:
        raise EmptyDataError()

    return data


async def get_data_one(url: str, **kwargs: Any) -> dict:
    """Get data from FMP endpoint and convert to schema."""
    data = await get_data(url, **kwargs)
    if isinstance(data, list):
        if len(data) == 0:
            raise ValueError("Expected dict, got empty list")

        try:
            data = {i: data[i] for i in range(len(data))} if len(data) > 1 else data[0]
        except TypeError as e:
            raise ValueError("Expected dict, got list of dicts") from e

View on GitHub (pinned to 3e071fcc2c)

Solutions

  1. Inspect the raw response for that endpoint with curl to see the current shape
  2. Update the openbb-platform FMP provider package (pip install -U openbb-fmp) - envelope changes are usually fixed quickly upstream
  3. If calling get_data_many yourself, pass the correct sub_dict key that holds the list (e.g. 'data' or 'historical')
  4. Report the shape change to the OpenBB maintainers if the latest provider still fails

Example fix

# before
data = await get_data_many(url)  # endpoint now returns {'data': [...]}

# after
data = await get_data_many(url, sub_dict='data')
Defensive patterns

Strategy: type-guard

Validate before calling

raw = await get_data(url)
if isinstance(raw, dict) and 'data' in raw and isinstance(raw['data'], list):
    raw = raw['data']  # unwrap known envelopes before calling get_data_many

Type guard

def is_list_of_dicts(data: object) -> bool:
    return isinstance(data, list) and all(isinstance(i, dict) for i in data)

Try / catch

try:
    data = await get_data_many(url, sub_dict='data')
except ValueError as e:
    if 'Expected list of dicts' in str(e):
        data = []  # endpoint shape changed - flag for investigation
    raise

Prevention

When it happens

Trigger: Calling an FMP endpoint through get_data_many whose current API version now returns {'data': [...]} or a singleton object; supplying a sub_dict that does not exist so data.get(sub_dict, []) is bypassed and the outer dict survives; FMP returning a dict-shaped error or 'limit reached' body.

Common situations: FMP changing an endpoint's response envelope between API versions; using a sub_dict name that no longer matches after FMP renames keys; stale openbb FMP provider package lagging an FMP API change.

Related errors


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