OpenBB-finance/OpenBB · error · OpenBBError

Unexpected data format. Expected dict, got: {type(data)}

Error message

Unexpected data format. Expected dict, got: {type(data)}

What it means

The type gate at price_target.py:301: if the decoded Benzinga /calendar/ratings payload is not a dict at all (list, str, None), the fetcher raises OpenBBError("Unexpected data format. Expected dict, got: {type(data)}"). The response_callback normally yields dicts, so a non-dict means the endpoint served a bare array or the body was parsed into something unexpected.

Source

Thrown at openbb_platform/providers/benzinga/openbb_benzinga/models/price_target.py:301

        """Return the raw data from the Benzinga endpoint."""
        # pylint: disable=import-outside-toplevel
        from openbb_benzinga.utils.helpers import response_callback
        from openbb_core.provider.utils.helpers import amake_request, get_querystring

        token = credentials.get("benzinga_api_key") if credentials else ""
        base_url = "https://api.benzinga.com/api/v2.1/calendar/ratings"
        query.limit = query.limit or 200
        querystring = get_querystring(query.model_dump(by_alias=True), [])

        url = f"{base_url}?{querystring}&token={token}"
        data = await amake_request(url, response_callback=response_callback, **kwargs)

        if isinstance(data, dict) and "ratings" not in data:
            raise OpenBBError(
                f"Unexpected data format. Expected 'ratings' key, got: {list(data.keys())}"
            )
        if not isinstance(data, dict):
            raise OpenBBError(
                f"Unexpected data format. Expected dict, got: {type(data)}"
            )
        if isinstance(data, dict) and not data.get("ratings"):
            raise EmptyDataError("No ratings data returned.")

        return data["ratings"]

    @staticmethod
    def transform_data(
        query: BenzingaPriceTargetQueryParams,
        data: list[dict],
        **kwargs: Any,
    ) -> list[BenzingaPriceTargetData]:
        """Return the transformed data."""
        results: list[BenzingaPriceTargetData] = []
        # Remove duplicated field with a URL
        for item in data:
            item.pop("url_calendar", None)

View on GitHub (pinned to 3e071fcc2c)

Solutions

  1. Log the raw body/type to identify what your network path actually received.
  2. Update openbb-benzinga — its response_callback owns normalization for this endpoint.
  3. If mocking in tests, return the documented dict shape ({"ratings": [...]}).
  4. Treat as a contract break to report rather than retry identically.

Example fix

# before
raise OpenBBError(f"Unexpected data format. Expected dict, got: {type(data)}")

# after
if isinstance(data, list):
    data = {"ratings": data}  # tolerate bare-array responses
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(data, dict):
    if isinstance(data, list):
        data = {"ratings": data}
    else:
        raise OpenBBError(f"unsupported Benzinga payload: {type(data)}")

Type guard

def is_benzinga_dict(data) -> bool:
    return isinstance(data, dict)

Try / catch

from openbb_core.app.model.abstract.error import OpenBBError
try:
    rows = await fetcher.a_fetch_data(query, credentials)
except OpenBBError as e:
    if "Expected dict" in str(e):
        logger.error("payload type drift from Benzinga: %s", e)  # report; do not blind-retry
    raise

Prevention

When it happens

Trigger: Benzinga returning a top-level JSON array on error paths, response_callback receiving HTML/text that decodes to str, or test/mocked responses returning lists.

Common situations: API revisions, transparent proxies or gateways rewriting responses, and unit tests that stub amake_request with list payloads.

Related errors


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