{"record":{"id":"7ad217a23afbfd8f","repo":"invoke-ai/InvokeAI","slug":"openai-image-edits-require-at-least-one-image-ini","errorCode":null,"errorMessage":"OpenAI image edits require at least one image (init image or reference image)","messagePattern":"OpenAI image edits require at least one image \\(init image or reference image\\)","errorType":"exception","errorClass":"ExternalProviderRequestError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/external_generation/providers/openai.py","lineNumber":76,"sourceCode":"                payload[\"response_format\"] = \"b64_json\"\n            if is_gpt_image:\n                if opts.get(\"quality\") and opts[\"quality\"] != \"auto\":\n                    payload[\"quality\"] = opts[\"quality\"]\n                if opts.get(\"background\") and opts[\"background\"] != \"auto\":\n                    payload[\"background\"] = opts[\"background\"]\n            response = requests.post(\n                f\"{base_url}/v1/images/generations\",\n                headers=headers,\n                json=payload,\n                timeout=timeout,\n            )\n        else:\n            images: list[PILImageType] = []\n            if request.init_image is not None:\n                images.append(request.init_image)\n            images.extend(reference.image for reference in request.reference_images)\n            if not images:\n                raise ExternalProviderRequestError(\n                    \"OpenAI image edits require at least one image (init image or reference image)\"\n                )\n\n            files: list[tuple[str, tuple[str, io.BytesIO, str]]] = []\n            image_field_name = \"image\" if len(images) == 1 else \"image[]\"\n            for index, image in enumerate(images):\n                image_buffer = io.BytesIO()\n                image.save(image_buffer, format=\"PNG\")\n                image_buffer.seek(0)\n                files.append((image_field_name, (f\"image_{index}.png\", image_buffer, \"image/png\")))\n\n            if request.mask_image is not None:\n                mask_buffer = io.BytesIO()\n                request.mask_image.save(mask_buffer, format=\"PNG\")\n                mask_buffer.seek(0)\n                files.append((\"mask\", (\"mask.png\", mask_buffer, \"image/png\")))\n\n            data: dict[str, object] = {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/external_generation/providers/openai.py#L58-L94","documentation":"ExternalProviderRequestError raised when the OpenAI provider is about to call the /v1/images/edits endpoint but the request carries no source images at all. Edits mode is selected whenever request.mode != 'txt2img' or reference_images exist, yet the collected images list (init_image plus reference_images) is empty — e.g. an img2img/variation job whose image inputs were never populated. OpenAI's edits API requires at least one image, so the provider fails fast with this actionable message.","triggerScenarios":"use_edits_endpoint is True (mode != 'txt2img' or reference_images non-empty) but request.init_image is None and request.reference_images resolves to zero usable images — e.g. a workflow node set to img2img without connecting an init image, reference_images containing only entries filtered out upstream, or mode mislabeled by the caller.","commonSituations":"User selects an edit/img2img OpenAI model but leaves the image input unconnected; a queue retry loses the binary init image; caller sets mode='edit' programmatically assuming references are optional; UI passes reference metadata without the actual PIL images.","solutions":["Provide an init image (request.init_image) or at least one reference image before invoking the OpenAI provider in edit mode.","Switch the request to mode 'txt2img' with no reference_images if pure text-to-image is intended, so the generations endpoint is used.","Check the calling workflow/graph: ensure the image input node is connected and the image data survives serialization.","Add a pre-submit validation in your integration that mirrors this check: if mode != 'txt2img' and not (init_image or reference_images): reject."],"exampleFix":"// before: edit-mode request without any image\nrequest = ExternalGenerationRequest(mode=\"edit\", prompt=\"...\", init_image=None, reference_images=[])\nresult = provider.generate(request)\n// after: fall back to txt2img when no image is supplied\nif request.mode != \"txt2img\" and request.init_image is None and not request.reference_images:\n    request = replace(request, mode=\"txt2img\")\nresult = provider.generate(request)","handlingStrategy":"validation","validationCode":"def validate_openai_edit_request(request) -> None:\n    if request.mode != \"txt2img\":\n        has_images = request.init_image is not None or bool(request.reference_images)\n        if not has_images:\n            raise ValueError(\"Edit mode requires an init image or at least one reference image\")","typeGuard":"def can_edit(request) -> bool:\n    return request.init_image is not None or len(request.reference_images) > 0","tryCatchPattern":"try:\n    result = provider.generate(request)\nexcept ExternalProviderRequestError as e:\n    if \"require at least one image\" in str(e):\n        request = replace(request, mode=\"txt2img\")  # degrade gracefully\n        result = provider.generate(request)\n    else:\n        raise","preventionTips":["Validate mode vs available images in your UI/graph before submitting the job.","Require the init-image input to be connected when an edit-capable model is selected.","Verify reference_images entries carry actual PIL images, not just metadata.","Reuse the provider's own rule: mode != 'txt2img' or reference_images implies images must exist."],"tags":["validation","openai","image-edit","missing-input","bad-request"],"backgroundTag":"missing-required-parameter","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}