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
- Inspect the raw response for that endpoint with curl to see the current shape
- Update the openbb-platform FMP provider package (pip install -U openbb-fmp) - envelope changes are usually fixed quickly upstream
- If calling get_data_many yourself, pass the correct sub_dict key that holds the list (e.g. 'data' or 'historical')
- 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
- Pin openbb-fmp versions in production and test upgrades against the endpoints you use
- When calling helpers directly, always pass the sub_dict for envelope-wrapped endpoints
- Monitor FMP API changelogs for response-shape changes
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
- Unexpected format of the response. -> Expected dict, got {st
- Expecting a list of dictionaries and received a dictionary.
- Expected dict, got list of dicts
- Unable to process supplied data.
- No data returned for the given symbols.
AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14).
Data as JSON: /api/errors/d4a49e5c06011a64.
Report an issue: GitHub.