BerriAI/litellm · error · ValueError

No choices in DeepSeek OCR response

Error message

No choices in DeepSeek OCR response

What it means

ValueError raised when the DeepSeek OCR response parses as JSON but contains no 'choices' array. The transformer expects a chat-style body ({'choices': [{'message': {'content': ...}}]}); a 200 response with any other shape fails here. The raw response text is debug-logged just before the raise, so verbose logging captures the actual body.

Source

Thrown at litellm/llms/vertex_ai/ocr/deepseek_transformation.py:270

        Args:
            model: Model name
            raw_response: Raw HTTP response from Vertex AI
            logging_obj: Logging object
            **kwargs: Additional arguments

        Returns:
            OCRResponse in standard format
        """
        verbose_logger.debug("Vertex AI DeepSeek OCR transform_ocr_response called")
        verbose_logger.debug("Raw response: %s", raw_response.text)

        try:
            response_json: Final = raw_response.json()

            # Extract OCR content from provider response
            choices: Final = response_json.get("choices", [])
            if not choices:
                raise ValueError("No choices in DeepSeek OCR response")

            message: Final = choices[0].get("message", {})
            content: Final = message.get("content", "")

            if not content:
                raise ValueError("No content in DeepSeek OCR response")

            # Try to parse content as JSON (OCR result might be JSON string)
            ocr_data = None
            try:
                # If content is a JSON string, parse it
                if isinstance(content, str) and content.strip().startswith("{"):
                    ocr_data = json.loads(content)
                elif isinstance(content, dict):
                    ocr_data = content
                else:
                    # If content is markdown text, create a single page with the markdown
                    ocr_data = {

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Enable verbose/debug logging to capture the 'Raw response: %s' line and see the actual body
  2. Confirm the model name routes to the DeepSeek OCR endpoint on Vertex
  3. If a proxy sits in front, verify it passes the Vertex body through unchanged
  4. Update litellm to the latest version in case the provider schema changed and litellm adapted
Defensive patterns

Strategy: try-catch

Try / catch

import litellm
litellm.verbose = True  # the transformer debug-logs the raw body before raising

try:
    resp = litellm.ocr(model=model, document=doc)
except ValueError as e:
    if 'No choices' in str(e):
        log.error('deepseek ocr: body without choices; check verbose logs for the raw response')
        resp = litellm.ocr(model=model, document=doc)  # single retry if transient
    else:
        raise

Prevention

When it happens

Trigger: Vertex returns 200 with an error or status object instead of choices; a schema change in the DeepSeek OCR model output; a proxy rewrites or strips the choices field.

Common situations: Model or endpoint version drift on Vertex; misrouted model name hitting a different endpoint; gateways that re-envelope responses.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/ee5d3f3e8c6dfe35. Report an issue: GitHub.