{"record":{"id":"1c5fd484f7d46bbb","repo":"BerriAI/litellm","slug":"unsupported-image-type-type-image-expected-by","errorCode":null,"errorMessage":"Unsupported image type: {type(image)}. Expected bytes, str (URL or file path), or file-like object.","messagePattern":"Unsupported image type: (.+?)\\. Expected bytes, str \\(URL or file path\\), or file-like object\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/black_forest_labs/image_edit/transformation.py","lineNumber":226,"sourceCode":"                response: Final = safe_get(litellm.module_level_client, image, timeout=60.0)\n                response.raise_for_status()\n                return response.content\n            else:\n                raise ValueError(\n                    \"Unsupported image input: plain string values that are not URLs are not accepted. \"\n                    \"Provide image bytes or a file-like object.\"\n                )\n        elif hasattr(image, \"read\"):\n            # File-like object\n            pos: Final = getattr(image, \"tell\", lambda: 0)()\n            if hasattr(image, \"seek\"):\n                image.seek(0)\n            data: Final = image.read()\n            if hasattr(image, \"seek\"):\n                image.seek(pos)\n            return data\n        else:\n            raise ValueError(\n                f\"Unsupported image type: {type(image)}. Expected bytes, str (URL or file path), or file-like object.\"\n            )\n\n    def transform_image_edit_request(\n        self,\n        model: str,\n        prompt: str | None,\n        image: FileTypes | None,\n        image_edit_optional_request_params: dict,\n        litellm_params: GenericLiteLLMParams,\n        headers: dict,\n    ) -> tuple[dict, RequestFiles]:\n        \"\"\"\n        Transform OpenAI-style request to Black Forest Labs request format.\n\n        BFL uses JSON body with base64-encoded images, not multipart/form-data.\n        \"\"\"\n        # Read and encode image","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/black_forest_labs/image_edit/transformation.py#L208-L244","documentation":"_read_image_bytes accepts only three shapes: bytes, URL-prefixed strings (plus one-level lists of them), and objects with a .read() method. Any other type — int, dict, None, PIL.Image, numpy array, pathlib.Path — falls to the final else and raises ValueError naming the received type. This is a client-side argument-type failure raised before any HTTP traffic.","triggerScenarios":"Passing image as a PIL.Image.Image, numpy.ndarray, pathlib.Path, dict, or None to image_edit with a black_forest_labs model.","commonSituations":"Feeding the output of an upstream Python imaging pipeline (PIL/numpy) straight into image_edit; passing Path objects since they feel string-like; forgetting the image argument entirely in a wrapper function (None).","solutions":["Convert before calling: PIL -> io.BytesIO via img.save(buf, format='PNG'); numpy -> img.tobytes(); Path -> path.read_bytes().","Always pass one of: bytes, https URL string, or an open binary file object.","Assert the type in your own wrapper so bad values fail loudly at your boundary, not inside LiteLLM."],"exampleFix":"# before\nlitellm.image_edit(model=..., image=pil_img, prompt=\"...\")\n\n# after\nimport io\nbuf = io.BytesIO(); pil_img.save(buf, format=\"PNG\")\nlitellm.image_edit(model=..., image=buf.getvalue(), prompt=\"...\")","handlingStrategy":"type-guard","validationCode":"import io\n\ndef coerce_image(x):\n    if hasattr(x, \"read\"): return x\n    if isinstance(x, bytes): return x\n    if isinstance(x, str) and x.startswith((\"http://\",\"https://\")): return x\n    if x.__class__.__name__ == \"PngImagePlugin\" or hasattr(x, \"save\"):\n        buf = io.BytesIO(); x.save(buf, format=\"PNG\"); return buf.getvalue()\n    if hasattr(x, \"tobytes\"): return x.tobytes()\n    raise TypeError(f\"cannot coerce {type(x)} to BFL image\")","typeGuard":"from typing import Any\n\ndef is_bfl_supported_image(x: Any) -> bool:\n    return (\n        isinstance(x, bytes)\n        or (isinstance(x, str) and x.startswith((\"http://\", \"https://\")))\n        or hasattr(x, \"read\")\n        or (isinstance(x, list) and x and is_bfl_supported_image(x[0]))\n    )","tryCatchPattern":"null","preventionTips":["Convert PIL/numpy/Path objects to bytes in your own adapter layer, never inside the call site.","Add unit tests asserting is_bfl_supported_image over every input path your pipeline produces.","Document to callers that the image parameter accepts bytes/URL/file-like only."],"tags":["bfl","image-input","type-error","validation","pil","numpy"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}