{"record":{"id":"fd62e452a16cbbab","repo":"BerriAI/litellm","slug":"gemini-image-edit-requires-at-least-one-image","errorCode":null,"errorMessage":"Gemini image edit requires at least one image.","messagePattern":"Gemini image edit requires at least one image\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/gemini/image_edit/transformation.py","lineNumber":96,"sourceCode":"        api_base: str | None,\n        litellm_params: dict,\n    ) -> str:\n        base_url = api_base or get_secret_str(\"GEMINI_API_BASE\") or self.DEFAULT_BASE_URL\n        base_url = base_url.rstrip(\"/\")\n        return f\"{base_url}/models/{model}:generateContent\"\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[str, Any],\n        litellm_params: GenericLiteLLMParams,\n        headers: dict,\n    ) -> tuple[dict[str, Any], RequestFiles | None]:\n        inline_parts: Final = self._prepare_inline_image_parts(image) if image else []\n        if not inline_parts:\n            raise ValueError(\"Gemini image edit requires at least one image.\")\n\n        # Build parts list with image and prompt (if provided)\n        parts: Final = inline_parts.copy()\n        if prompt is not None and prompt != \"\":\n            parts.append({\"text\": prompt})\n\n        contents: Final = [\n            {\n                \"parts\": parts,\n            }\n        ]\n\n        request_body: Final[dict[str, Any]] = {\"contents\": contents}\n\n        request_body[\"generationConfig\"] = get_gemini_image_generation_config(\n            model=model,\n            optional_params=image_edit_optional_request_params,\n        )","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/gemini/image_edit/transformation.py#L78-L114","documentation":"Request-shape validation in GeminiImageEditConfig.transform_image_edit_request. Gemini image edit inlines the input image(s) as base64 inlineData parts; if the image argument is None, an empty list, or a list whose entries are all None, the inline parts list is empty and this ValueError is raised before any HTTP call.","triggerScenarios":"litellm.image_edit(model='gemini/gemini-2.5-flash-image', prompt='...') with image omitted; image=[] (e.g. an upload step upstream produced an empty list); image=[None] from an optional form field that was never set.","commonSituations":"Web forms where the image field is optional but Gemini edit requires it; code paths shared with OpenAI images/edits where image is also required but validation happens elsewhere; upstream file-read bugs silently yielding empty payloads.","solutions":["Always pass image as bytes, BytesIO, BufferedReader, or a non-empty list of those (OpenAI-style path strings/tuples are NOT accepted — see the unsupported-image-type error)","Validate at the API boundary: reject requests without an image before calling litellm","If the image is optional in your product, branch to litellm.image_generation (prompt-only) instead of image_edit","Log the received image type/size at the edge to catch empty uploads early"],"exampleFix":"# before\nresp = litellm.image_edit(model='gemini/gemini-2.5-flash-image', prompt='remove background')\n# ValueError: Gemini image edit requires at least one image.\n\n# after - enforce at the boundary; fall back to generation when no image\nif image_bytes:\n    resp = litellm.image_edit(model='gemini/gemini-2.5-flash-image', prompt=prompt, image=image_bytes, api_key=KEY)\nelse:\n    resp = litellm.image_generation(model='gemini/2.0-flash-preview-image-generation', prompt=prompt, api_key=KEY)","handlingStrategy":"validation","validationCode":"def has_editable_image(image) -> bool:\n    if image is None:\n        return False\n    imgs = image if isinstance(image, list) else [image]\n    return any(img is not None for img in imgs)\n\nassert has_editable_image(request.image), 'gemini image_edit requires a non-empty image'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make the image field mandatory at your API boundary for edit endpoints","Reject empty uploads before they reach litellm (check Content-Length / bytes read)","Use prompt-only generation (image_generation) for the no-image case instead of image_edit"],"tags":["gemini","image-edit","request-validation","missing-parameter"],"backgroundTag":"missing-required-argument","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}