BerriAI/litellm · error · ValueError

Nova Canvas image edit does not support tuple FileTypes…

Error message

Nova Canvas image edit does not support tuple FileTypes. Pass a file-like object, bytes, or a base64-encoded string.

What it means

The FileTypes union used by OpenAI-style image APIs includes multipart tuple forms like (filename, bytes, content_type). Nova Canvas image edit sends JSON with base64 fields to Bedrock InvokeModel, not multipart, and its encoder only accepts file-like objects, bytes, base64 strings, and os.PathLike — tuples are rejected explicitly.

Solutions

  1. Pass the raw bytes: image=png_bytes
  2. Pass a file object (open('cat.png', 'rb')), a base64-encoded string, or a pathlib.Path
  3. Unpack tuples before the call: image = tup[1] if isinstance(tup, tuple) else tup

Example fix

# before
img = ("cat.png", png_bytes, "image/png")
resp = litellm.image_edit(model="bedrock/amazon.nova-canvas-v1:0", image=img, prompt="...")

# after
resp = litellm.image_edit(model="bedrock/amazon.nova-canvas-v1:0", image=png_bytes, prompt="...")
Defensive patterns

Strategy: type-guard

Validate before calling

def normalize_file_types(value):
    """Convert multipart tuples to bytes for Nova Canvas edit calls."""
    if isinstance(value, tuple):
        for part in value:
            if isinstance(part, (bytes, bytearray)):
                return bytes(part)
        raise ValueError("tuple FileTypes must contain bytes")
    return value

image = normalize_file_types(raw_upload)

Type guard

def is_nova_canvas_file_types(value) -> bool:
    """True when value is accepted by Nova Canvas: file-like, bytes, base64 str, PathLike."""
    if value is None:
        return False
    if isinstance(value, tuple):
        return False
    return (
        callable(getattr(value, "read", None))
        or isinstance(value, (bytes, bytearray, str))
        or isinstance(value, os.PathLike)
    )

Try / catch

try:
    resp = litellm.image_edit(...)
except ValueError as e:
    if "does not support tuple FileTypes" in str(e):
        resp = litellm.image_edit(..., image=image_tuple[1])  # bytes element
    else:
        raise

Prevention

When it happens

Trigger: image=('/tmp/cat.png', png_bytes, 'image/png') (or the same shape for mask=) — typically produced by helpers that build multipart file tuples for form uploads.

Common situations: Reusing OpenAI SDK / FastAPI / requests multipart file-building code; storing uploads as (name, bytes, mime) tuples and forwarding them to image_edit.

Related errors


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

Appendix: source

Thrown at litellm/llms/bedrock/image_edit/amazon_nova_canvas_image_edit_transformation.py:148

def _file_types_to_b64(image: FileTypes | None) -> str:
    """Encode OpenAI image input to base64 string for Nova Canvas."""
    if image is None:
        raise ValueError("Nova Canvas image edit requires an image input")
    if hasattr(image, "read") and callable(getattr(image, "read", None)):
        if hasattr(image, "seek"):
            image.seek(0)
        image_bytes: Final = image.read()
        return base64.b64encode(image_bytes).decode("utf-8")
    if isinstance(image, bytes):
        return base64.b64encode(image).decode("utf-8")
    if isinstance(image, str):
        return image
    if isinstance(image, os.PathLike):
        with open(image, "rb") as f:
            return base64.b64encode(f.read()).decode("utf-8")
    if isinstance(image, tuple):
        raise ValueError(
            "Nova Canvas image edit does not support tuple FileTypes. "
            "Pass a file-like object, bytes, or a base64-encoded string."
        )
    return base64.b64encode(bytes(image)).decode("utf-8")


def _supports_nova_canvas_image_edit_from_model_cost(model: str) -> bool:
    """
    True when model_cost has supports_nova_canvas_image_edit for a resolved catalog key.

    get_model_info / ModelInfoBase omit arbitrary JSON keys, so we read model_cost
    directly (same idea as supports_* bare_entry fallback).
    """
    import litellm as _litellm

    if not model:
        return False

View on GitHub (pinned to 77b7c6c40c)