Comfy-Org/ComfyUI · error · Exception

Mask and Image must be the same size

Error message

Mask and Image must be the same size

What it means

Thrown by the Dall-E 2 image-edit path in nodes_openai.py when the supplied mask tensor's spatial dimensions do not match the input image's. The RGBA edit payload is built from the image and the mask is written into its alpha channel, so mismatched sizes would corrupt the payload. Checked as mask.shape[1:] != image.shape[1:-1].

Source

Thrown at comfy_api_nodes/nodes_openai.py:219

        validate_string(prompt, strip_whitespace=False)
        model = "dall-e-2"
        path = "/proxy/openai/images/generations"
        content_type = "application/json"
        request_class = OpenAIImageGenerationRequest
        img_binary = None

        if image is not None and mask is not None:
            path = "/proxy/openai/images/edits"
            content_type = "multipart/form-data"
            request_class = OpenAIImageEditRequest

            input_tensor = image.squeeze().cpu()
            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,

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Resize the mask to exactly the image's HxW before connecting it (e.g. a resize node matching the image)
  2. Load the mask from the same LoadImage node output so dimensions stay coupled
  3. Verify shapes: mask.shape[1:] == image.shape[1:-1] before the edit call
  4. If the mask must come from elsewhere, generate it from the image itself (e.g. MaskEditor) so it inherits size

Example fix

// before
image  # (1, 1024, 1024, 3)
mask    # (1, 512, 512)
// after
import torch
mask = torch.nn.functional.interpolate(mask.unsqueeze(1).float(), size=image.shape[1:3], mode='nearest').squeeze(1)
Defensive patterns

Strategy: validation

Validate before calling

assert mask.shape[1:] == image.shape[1:-1], f"mask {tuple(mask.shape)} != image {tuple(image.shape)}"

Type guard

def mask_matches_image(mask, image) -> bool:
    return mask.shape[1:] == image.shape[1:-1]

Prevention

When it happens

Trigger: Calling OpenAIImageEdit (Dall-E 2 path) with a mask loaded at a different resolution than the image (e.g. 512x512 image with a 1024x1024 mask), or masks coming from a different workflow branch.

Common situations: Loading a mask PNG exported at another size; using an upscaled/downscaled image while keeping the original mask; forgetting that LoadImage returns the mask at the image file's own resolution.

Related errors


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