GPT Image 2.5 mask checklist: same size, alpha, under 50MB

Check your mask before a paid GPT Image 2.5 edit: same size and format as the image, an alpha channel, under 50MB. A short Python preflight for Sume mask_url.

4 min readSume
All posts

Before you send a mask_url edit, confirm three things about the mask file: it has the same dimensions and format as the image, it has an alpha channel, and both files are under 50MB. The script below checks all of it for free, before Sume starts a paid generation.

These are OpenAI's published rules in its image generation guide: "The image to edit and mask must be of the same format and size (less than 50MB)," and masks require an alpha channel. Sume's Image API exposes mask_url for ChatGPT Image 2.5 edits, so a mask that breaks the rules is a wasted call.

Which rules apply, and where do they come from?

Only the OpenAI page was read for the numbers. Sume's docs add that the mask URL must be public HTTPS, and that localhost, private-network, non-HTTPS and non-image responses are rejected before generation starts.

Mask rules for a GPT Image 2.5 edit (read 2026-10-02)
RuleSourceChecked by the script
Same size as the imageOpenAI guideYes
Same format as the imageOpenAI guideYes
Alpha channel presentOpenAI guideYes
Each file under 50MBOpenAI guideYes
Public HTTPS URLSume Image API docsYes (scheme only)

Why check locally?

A failed Sume image generation is not billed, but a mask that passes validation and still looks wrong is billed in full, and that is the expensive case. A local check catches mismatched sizes, which are the usual mistake after someone exports a mask from a resized copy of the photo.

The docs also say that an unfetchable input is rejected with an image_not_fetchable style error, so confirm the URLs open in a browser without logging in.

Sume also publishes the sizes GPT Image 2.5 accepts for outputs: both edges multiples of 16, maximum edge 3840, aspect ratio at most 3:1, and 655,360 to 8,294,400 pixels. Those are output rules, separate from the mask rules here, but an edit uses the reference's shape when aspect_ratio is auto, so a reference outside those bounds is worth catching in the same script. The earlier size validator post has that code.

The preflight script

It downloads both files, reads the first with Pillow, and prints every problem it finds. Install requests and pillow.

import sys, requests
from io import BytesIO
from PIL import Image

def load(url):
    if not url.startswith("https://"):
        raise ValueError(f"not https: {url}")
    data = requests.get(url, timeout=30).content
    return len(data), Image.open(BytesIO(data))

def check(image_url, mask_url):
    (n1, img), (n2, mask) = load(image_url), load(mask_url)
    errs = []
    if img.size != mask.size: errs.append(f"size {img.size} vs {mask.size}")
    if img.format != mask.format: errs.append(f"format {img.format} vs {mask.format}")
    if "A" not in mask.getbands(): errs.append(f"no alpha: {mask.mode}")
    if max(n1, n2) >= 50 * 1024 * 1024: errs.append("file over 50MB")
    return errs

if __name__ == "__main__":
    problems = check(sys.argv[1], sys.argv[2])
    print("\n".join(problems) or "mask looks valid")
    sys.exit(1 if problems else 0)

What does a valid mask still not guarantee?

It guarantees the request is well formed, not that the model respects the edges. See the earlier post on edits that leaked outside the mask, and keep the preserve instruction in the prompt. Treat the mask as a strong hint.

If you edit with several references, work out which image the mask belongs to before you send, as covered in the multi-reference mask post linked below.

A last practical point: serve the mask from storage that returns the raw file with an image content type. A page that wraps the picture in HTML, or a link that redirects to a login, fails the fetch rules even though it opens fine in a browser tab. Test with curl -I and look for a content-type that starts with image/.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume