BerriAI/litellm · error · ValueError

image_response must be of type ImageResponse got type={type(

Error message

image_response must be of type ImageResponse got type={type(image_response)}

What it means

Litellm computes Vertex AI image-edit cost as output_cost_per_image x number of returned images. Before doing that math, the cost calculator asserts the object it was handed is a litellm.types.utils.ImageResponse. If a custom cost handler, router callback, or forked internal passes anything else (dict, httpx.Response, None), this ValueError is raised. It is an internal-contract check, not an API response error.

Source

Thrown at litellm/llms/vertex_ai/image_edit/cost_calculator.py:29

def cost_calculator(
    model: str,
    image_response: Any,
) -> float:
    """
    Vertex AI image edit cost calculator.

    Mirrors image generation pricing: charge per returned image based on
    model metadata (`output_cost_per_image`).
    """
    model_info: Final = litellm.get_model_info(
        model=model,
        custom_llm_provider="vertex_ai",
    )

    output_cost_per_image: Final[float] = model_info.get("output_cost_per_image") or 0.0

    if not isinstance(image_response, ImageResponse):
        raise ValueError(f"image_response must be of type ImageResponse got type={type(image_response)}")

    num_images: Final = len(image_response.data or [])
    return output_cost_per_image * num_images

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Pass the ImageResponse object exactly as returned by litellm.image_edit()/litellm.aimage_edit() — do not call .json() or rebuild a dict
  2. If you construct one yourself, build litellm.types.utils.ImageResponse(data=[ImageObject(b64_json=...)]) instead of a plain dict
  3. In custom cost handlers, mirror the default: isinstance(resp, ImageResponse) check first, then cost = price * len(resp.data or [])
  4. If you only have raw JSON, parse it into ImageResponse before calling the calculator

Example fix

# before
cost = cost_calculator(model, image_response=resp.json())  # dict -> raises

# after
from litellm.types.utils import ImageResponse
assert isinstance(resp, ImageResponse)
cost = cost_calculator(model, image_response=resp)
Defensive patterns

Strategy: type-guard

Validate before calling

from litellm.types.utils import ImageResponse

if not isinstance(image_response, ImageResponse):
    raise TypeError(f'cost calculation requires ImageResponse, got {type(image_response)}')

Type guard

from litellm.types.utils import ImageResponse

def is_image_response(obj) -> bool:
    return isinstance(obj, ImageResponse)

Try / catch

try:
    cost = cost_calculator(model, image_response)
except ValueError as e:
    if 'must be of type ImageResponse' in str(e):
        log.error('cost hook received %s, skipping', type(image_response))
    else:
        raise

Prevention

When it happens

Trigger: Calling litellm.llms.vertex_ai.image_edit.cost_calculator.cost_calculator() (or wiring it via a custom_cost_handler / cost tracking hook) with response.json() output, an OpenAI SDK object, or a hand-built dict instead of the ImageResponse instance returned by litellm.image_edit(). Unit tests that mock the response with a plain dict also hit it.

Common situations: Writing a custom pricing callback for vertex_ai image-edit models; upgrading litellm versions where the cost-calculation signature tightened to require ImageResponse; helper code that re-serializes responses before passing them to cost tracking.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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