{"record":{"id":"d4a49e5c06011a64","repo":"OpenBB-finance/OpenBB","slug":"expected-list-of-dicts-got-dict","errorCode":null,"errorMessage":"Expected list of dicts, got dict","messagePattern":"Expected list of dicts, got dict","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"openbb_platform/providers/fmp/openbb_fmp/utils/helpers.py","lineNumber":121,"sourceCode":"\n    Parameters\n    ----------\n    url: str\n        The URL to get the data from.\n    sub_dict: Optional[str]\n        The sub-dictionary to use.\n\n    Returns\n    -------\n    list[dict]\n        Dictionary of data.\n    \"\"\"\n    data = await get_data(url, **kwargs)\n\n    if sub_dict and isinstance(data, dict):\n        data = data.get(sub_dict, [])\n    if isinstance(data, dict):\n        raise ValueError(\"Expected list of dicts, got dict\")\n    if len(data) == 0:\n        raise EmptyDataError()\n\n    return data\n\n\nasync def get_data_one(url: str, **kwargs: Any) -> dict:\n    \"\"\"Get data from FMP endpoint and convert to schema.\"\"\"\n    data = await get_data(url, **kwargs)\n    if isinstance(data, list):\n        if len(data) == 0:\n            raise ValueError(\"Expected dict, got empty list\")\n\n        try:\n            data = {i: data[i] for i in range(len(data))} if len(data) > 1 else data[0]\n        except TypeError as e:\n            raise ValueError(\"Expected dict, got list of dicts\") from e\n","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/providers/fmp/openbb_fmp/utils/helpers.py#L103-L139","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\ndata = await get_data_many(url)  # endpoint now returns {'data': [...]}\n\n# after\ndata = await get_data_many(url, sub_dict='data')","handlingStrategy":"type-guard","validationCode":"raw = await get_data(url)\nif isinstance(raw, dict) and 'data' in raw and isinstance(raw['data'], list):\n    raw = raw['data']  # unwrap known envelopes before calling get_data_many","typeGuard":"def is_list_of_dicts(data: object) -> bool:\n    return isinstance(data, list) and all(isinstance(i, dict) for i in data)","tryCatchPattern":"try:\n    data = await get_data_many(url, sub_dict='data')\nexcept ValueError as e:\n    if 'Expected list of dicts' in str(e):\n        data = []  # endpoint shape changed - flag for investigation\n    raise","preventionTips":["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"],"tags":["fmp","type-mismatch","api-contract","response-shape"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}