BerriAI/litellm · error · ValueError
Max recursion depth {max_depth} reached while reading image
Error message
Max recursion depth {max_depth} reached while reading image bytes for Black Forest Labs image edit. What it means
_read_image_bytes normalizes diverse image inputs (bytes, list, URL string, file-like object) into raw bytes, recursing one level per list wrapper. A depth counter guards against pathologically nested lists; exceeding DEFAULT_MAX_RECURSE_DEPTH raises ValueError. In practice this almost always means an empty or unexpectedly nested structure (e.g. a list of lists with no bytes at the leaf) rather than genuine 10+ level nesting.
Source
Thrown at litellm/llms/black_forest_labs/image_edit/transformation.py:198
) -> str:
"""
Get the complete URL for the Black Forest Labs API request.
"""
base_url: str = api_base or get_secret_str("BFL_API_BASE") or DEFAULT_API_BASE
base_url = base_url.rstrip("/")
endpoint: Final = self._get_model_endpoint(model)
return f"{base_url}{endpoint}"
def _read_image_bytes(
self,
image: Any,
depth: int = 0,
max_depth: int = DEFAULT_MAX_RECURSE_DEPTH,
) -> bytes:
"""Read image bytes from various input types."""
if depth > max_depth:
raise ValueError(
f"Max recursion depth {max_depth} reached while reading image bytes for Black Forest Labs image edit."
)
if isinstance(image, bytes):
return image
elif isinstance(image, list):
# If it's a list, take the first image
return self._read_image_bytes(image[0], depth=depth + 1, max_depth=max_depth)
elif isinstance(image, str):
if image.startswith(("http://", "https://")):
response: Final = safe_get(litellm.module_level_client, image, timeout=60.0)
response.raise_for_status()
return response.content
else:
raise ValueError(
"Unsupported image input: plain string values that are not URLs are not accepted. "
"Provide image bytes or a file-like object."
)
elif hasattr(image, "read"):View on GitHub (pinned to 6c2dcb801b)
Solutions
- Pass the image directly: raw bytes, a single URL string, or one file-like object.
- If you must use a list, use exactly one level: image=[b"..."].
- Inspect the value right before the call: print(type(image), len(image)) down the nesting to find where extra wrappers come from.
- Fix the upstream code that keeps collecting the image into another list on every layer.
Example fix
# before img = load_bytes() litellm.image_edit(model=..., image=[[[img]]], prompt="...") # after img = load_bytes() litellm.image_edit(model=..., image=img, prompt="...")
Defensive patterns
Strategy: validation
Validate before calling
def flat_image(x, depth=0):
while isinstance(x, list):
if not x: raise ValueError("empty image list")
x = x[0]; depth += 1
if depth > 5: raise ValueError("image wrapped in too many lists")
return x
image = flat_image(image) Type guard
from typing import Any
def is_recursion_safe_image(x: Any, depth: int = 0) -> bool:
if isinstance(x, (bytes,)) or (isinstance(x, str) and x.startswith(("http://","https://"))) or hasattr(x, "read"):
return True
if isinstance(x, list) and x:
return depth < 5 and is_recursion_safe_image(x[0], depth + 1)
return False Try / catch
null
Prevention
- Never wrap the image argument in a list at more than one level.
- In wrapper functions, accept one image parameter and pass it through unchanged.
- Assert the leaf type (bytes/URL/file-like) before calling image_edit.
When it happens
Trigger: Passing image as deeply nested lists, e.g. [[[...[b"..."]...]]], or a structure whose leaf elements are never bytes/str/file-like so each recursion only descends (an empty list would IndexError first, but nested single-element lists chain to the depth cap).
Common situations: Wrapping the image argument multiple times by mistake (e.g. image=[image_list] where image_list was already a list); passing a parsed JSON/AI-message content array instead of the media payload; programmatic construction of the image arg that accumulates wrappers across layers.
Related errors
- Unsupported image input: plain string values that are not UR
- Unsupported image type: {type(image)}. Expected bytes, str (
- Unknown BFL image edit model: {model_name}. Supported models
- BFL error: {response_data['errors']}
- Parameter {k} is not supported for model {model}. Supported
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/487f85b0dfbaa2f2.
Report an issue: GitHub.