Comfy-Org/ComfyUI · error · Exception

Dall-E 2 image editing requires an image AND a mask

Error message

Dall-E 2 image editing requires an image AND a mask

What it means

Raised by the Dall-E 2 image-edit node when exactly one of image or mask is provided. Dall-E 2's /images/edits endpoint requires both an input image and a mask, so the XOR branch (image is not None or mask is not None, but not both) throws this Exception before any request is sent.

Source

Thrown at comfy_api_nodes/nodes_openai.py:232

            height, width, channels = input_tensor.shape
            rgba_tensor = torch.ones(height, width, 4, device="cpu")
            rgba_tensor[:, :, :channels] = input_tensor

            if mask.shape[1:] != image.shape[1:-1]:
                raise Exception("Mask and Image must be the same size")
            rgba_tensor[:, :, 3] = 1 - mask.squeeze().cpu()

            rgba_tensor = downscale_image_tensor(rgba_tensor.unsqueeze(0)).squeeze()

            image_np = (rgba_tensor.numpy() * 255).astype(np.uint8)
            img = Image.fromarray(image_np)
            img_byte_arr = BytesIO()
            img.save(img_byte_arr, format="PNG")
            img_byte_arr.seek(0)
            img_binary = img_byte_arr  # .getvalue()
            img_binary.name = "image.png"
        elif image is not None or mask is not None:
            raise Exception("Dall-E 2 image editing requires an image AND a mask")

        response = await sync_op(
            cls,
            ApiEndpoint(path=path, method="POST"),
            response_model=OpenAIImageGenerationResponse,
            data=request_class(
                model=model,
                prompt=prompt,
                n=n,
                size=size,
                seed=seed,
            ),
            files=(
                {
                    "image": ("image.png", img_binary, "image/png"),
                }
                if img_binary
                else None

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Connect both an image and a mask to the edit node, or disconnect both for pure generation
  2. Switch to the gpt-image-1/gpt-image-2 path if you want mask-optional editing
  3. Verify both wires survived workflow edits (visual inspection of the node inputs)

Example fix

// before
edit(image=my_image, mask=None)   # Dall-E 2: raises
// after
edit(image=my_image, mask=my_mask)  # both provided
// or use the gpt-image model path for maskless editing
Defensive patterns

Strategy: validation

Validate before calling

if (image is None) != (mask is None):
    raise ValueError("Dall-E 2 edit needs both image and mask, or neither")

Type guard

def valid_dalle2_edit_inputs(image, mask) -> bool:
    return (image is None) == (mask is None)

Prevention

When it happens

Trigger: Calling the edit node with only a mask connected (no image) or only an image connected (no mask) while the Dall-E 2 edit path is selected.

Common situations: User switches intent from inpainting to image-variation but leaves one socket empty; workflow refactoring drops one of the two links; assuming gpt-image-1 semantics (mask optional) on the Dall-E 2 model.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/963129283ebfcf8c. Report an issue: GitHub.