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
- Pass the raw bytes: image=png_bytes
- Pass a file object (open('cat.png', 'rb')), a base64-encoded string, or a pathlib.Path
- 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
- Standardize on bytes for in-memory images crossing API boundaries
- Adapt multipart tuples from web frameworks to raw bytes at the edge
- Unit-test your upload normalization with every FileTypes shape you accept
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
- Amazon Nova Canvas INPAINTING requires either maskPrompt or…
- Amazon Nova Canvas requires a text prompt. Pass a non-empty…
- Nova Canvas image edit requires an image input
- OUTPAINTING requires either a mask image or a mask prompt…
- Unsupported Amazon Nova Canvas taskType
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)