OpenBB-finance/OpenBB · error · ValueError

Expected dict, got list of dicts

Error message

Expected dict, got list of dicts

What it means

Raised by openbb_fmp get_data_one when the response is a list whose element access raises TypeError - in practice a list of non-subscriptable items (e.g. a list of strings or numbers) where a list of dicts was expected. For a normal multi-dict list the range-index comprehension succeeds and returns a dict of dicts, so this fires on truly malformed payloads.

Source

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

    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

    return data


def most_recent_quarter(base: date | None = None) -> date:
    """Get the most recent quarter date."""
    if base is None:
        base = date.today()
    base = min(base, date.today())  # This prevents dates from being in the future
    exacts = [(3, 31), (6, 30), (9, 30), (12, 31)]
    for exact in exacts:
        if base.month == exact[0] and base.day == exact[1]:
            return base
    if base.month < 4:
        return date(base.year - 1, 12, 31)
    if base.month < 7:
        return date(base.year, 3, 31)
    if base.month < 10:

View on GitHub (pinned to 3e071fcc2c)

Solutions

  1. Curl the URL with the same key and inspect the exact JSON type of the list elements
  2. Update openbb-fmp to the latest version to pick up endpoint fixes
  3. Verify the URL template matches the current FMP API docs (v3 vs v4 paths)
  4. Treat as transient if FMP status page shows degradation and retry later
Defensive patterns

Strategy: type-guard

Validate before calling

raw = await get_data(url)
if isinstance(raw, list) and raw and not isinstance(raw[0], dict):
    raise RuntimeError(f'FMP returned malformed list payload: {raw!r:.200}')

Type guard

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

Try / catch

try:
    data = await get_data_one(url)
except ValueError as e:
    if 'list of dicts' in str(e):
        log.error('FMP response shape changed for %s', url)
    raise

Prevention

When it happens

Trigger: An FMP endpoint normally returning [{...}] suddenly returning ['msg1','msg2'] or [1,2,3]; passing a URL that hits an FMP error/maintenance page whose JSON body is a plain list of strings.

Common situations: FMP API changes or intermittent maintenance payloads; pointing base_url at the wrong API version so the endpoint resolves to a different resource; provider/openbb version skew after FMP updates.

Related errors


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