BerriAI/litellm · error · TypeError

{service_name} returned non-dict JSON ({type(result).__name_

Error message

{service_name} returned non-dict JSON ({type(result).__name__}); expected OpenAI chat completion shape or empty object.

What it means

Rubrik's shared _post helper (used by prompt and response moderation) does raise_for_status() then requires http_response.json() to be a dict — it expects an OpenAI-chat-completion-like decision object or {}. If the service returns a JSON list, string, or number, it raises TypeError naming the service and the offending JSON type.

Source

Thrown at litellm/integrations/rubrik.py:1032

    # -- Webhook services ------------------------------------------------------

    async def _post_json(self, endpoint: str, payload: Mapping[str, object], service_name: str) -> Mapping[str, Any]:
        """POST ``payload`` to a Rubrik webhook and return its dict response.

        Raises:
            Exception: If the service is unavailable or returns an error.
            TypeError: If the response JSON is not a dict.
        """
        verbose_logger.debug("Sending request to %s: %s", service_name, endpoint)
        http_response: Final = await self.moderation_client.post(
            endpoint,
            json=payload,
            headers=self._headers,
        )
        http_response.raise_for_status()
        result: Final[object] = http_response.json()
        if not isinstance(result, dict):
            raise TypeError(
                f"{service_name} returned non-dict JSON "
                f"({type(result).__name__}); expected OpenAI chat completion "
                "shape or empty object."
            )
        return result

    async def _post_to_response_moderation_endpoint(
        self,
        response_data: Mapping[str, object],
        request_data: Mapping[str, object],
    ) -> Mapping[str, Any]:
        """Post the ``{request, response}`` envelope to the after_completion
        webhook and return its (possibly rewritten) response.

        Args:
            response_data: The OpenAI-formatted response payload to send.
            request_data: Original LLM request data to include alongside
                the response for additional context. Empty dict if unavailable.

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Reproduce the POST (endpoint and payload are logged in the debug line above the raise) and inspect the raw JSON body
  2. If a middleware/gateway transforms responses, fix it to pass through the original object shape
  3. Upgrade litellm for fixes to Rubrik response parsing; if the endpoint legitimately returns non-dict JSON, report it — the client cannot evaluate it

Example fix

# mock server returning a list — triggers TypeError
# before
return Response(json.dumps([{"decision": "allow"}]))  # -> TypeError: non-dict JSON (list)

# after
return Response(json.dumps({"choices": [{"message": {"content": "allow"}}]}))
Defensive patterns

Strategy: type-guard

Validate before calling

result = http_response.json()
if not isinstance(result, dict):
    raise TypeError(f"unexpected moderation payload: {type(result).__name__}")

Type guard

from typing import Any, TypeGuard

def is_moderation_dict(v: Any) -> TypeGuard[dict]:
    return isinstance(v, dict) or v == {}

Try / catch

try:
    result = await rubrik._post_to_moderation_endpoint(endpoint, payload)
except TypeError as e:
    if "non-dict JSON" in str(e):
        logger.error("moderation endpoint returned unexpected JSON shape; failing open")
        result = {}
    else:
        raise

Prevention

When it happens

Trigger: The Rubrik moderation endpoint (or anything fronting it — a gateway, mock, or proxy) returns a JSON array (e.g. a list of findings) instead of an object; a misrouted URL that returns a different JSON API shape; a mock server returning '[]' or '"allowed"'.

Common situations: Version mismatch between the Rubrik Moderation API and this client; pointing RUBRIK_WEBHOOK_URL at a custom middleware that wraps responses in a list; testing against stub servers that return simplistic JSON.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/8cb9c8ddd713d685. Report an issue: GitHub.