HKUDS/DeepTutor · error · GenerationProviderError

Image response had no image in the assistant message.

Error message

Image response had no image in the assistant message.

What it means

_extract_sources walked the assistant message content parts but found none whose image_url.url / url started with data:image or http, so the sources list is empty. This fires even though the response contained a message — the message simply had no recognizable inline image.

Source

Thrown at deeptutor/services/imagegen/adapters/chat_completions.py:96

        for choice in choices or []:
            message = (choice or {}).get("message") or {}
            for image in message.get("images") or []:
                if not isinstance(image, dict):
                    continue
                src = (image.get("image_url") or {}).get("url") or image.get("url")
                if isinstance(src, str) and src:
                    sources.append(src)
            # Fallback: some variants nest images in the content parts array.
            content = message.get("content")
            if isinstance(content, list):
                for part in content:
                    if not isinstance(part, dict):
                        continue
                    src = (part.get("image_url") or {}).get("url") or part.get("url")
                    if isinstance(src, str) and src.startswith(("data:image", "http")):
                        sources.append(src)
        if not sources:
            raise GenerationProviderError("Image response had no image in the assistant message.")
        return sources

    async def _materialize(self, client: httpx.AsyncClient, src: str) -> tuple[bytes, str]:
        if src.startswith("data:"):
            header, _, encoded = src.partition(",")
            if not encoded:
                raise GenerationProviderError("Malformed image data URI.")
            content_type = header[5:].split(";", 1)[0].strip() or "image/png"
            return base64.b64decode(encoded), content_type
        resp = await client.get(src)
        raise_for_provider(resp, "Image download")
        content_type = resp.headers.get("content-type") or "image/png"
        if not content_type.startswith("image/"):
            content_type = "image/png"
        return resp.content, content_type


__all__ = ["ChatCompletionsImagegenAdapter"]

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Log the raw response JSON and identify where the image reference actually lives
  2. If the field differs, normalize upstream or use a provider/adapter matching the response shape (e.g. the /images/generations adapter)
  3. Ensure the model actually emitted an image and not a text refusal
Defensive patterns

Strategy: try-catch

Type guard

def has_recognized_image_source(part: dict) -> bool:
    src = (part.get("image_url") or {}).get("url") or part.get("url")
    return isinstance(src, str) and src.startswith(("data:image", "http"))

Try / catch

try:
    sources = adapter._extract_sources(resp)
except GenerationProviderError:
    logger.warning("unrecognized image shape: %s", resp.json())
    raise

Prevention

When it happens

Trigger: The model returns images as markdown links, a different field name, or a URL scheme not starting with http/data:image; content parts exist but are text-only; the provider wraps image data in a proprietary shape.

Common situations: Non-OpenAI-compatible gateways returning vendor-specific image fields; model returning a relative URL or non-image content type; response shape drift after a provider API version change.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/fcda2c358daea6de. Report an issue: GitHub.