Mask file checklist for GPT Image 2.5: alpha, same size, under 50 MB
OpenAI says an edit mask must match the image in format and size, stay under 50 MB, and carry an alpha channel. Check your file before sending mask_url to Sume.

Before you send mask_url to GPT Image 2.5 on Sume, check three things from OpenAI's image generation guide: the image and the mask must match in format and size, each must be under 50 MB, and the mask must have an alpha channel. Sume itself documents mask_url as an optional public HTTPS URL for ChatGPT Image 2.5 edits, and does not restate the file rules, so follow OpenAI's.
The checklist
OpenAI's guide describes mask-based editing as providing an image and a mask to replace specific areas. Its note on masks says images and masks must match in format and size and be less than 50 MB, and that masks must contain an alpha channel. Treat these as the rules to meet before the request leaves your server, because a rejected mask costs a round trip.
| Check | Rule | How to test |
|---|---|---|
| Format | Image and mask match | Both PNG, or both the same format |
| Size | Same pixel dimensions | Compare width and height |
| File size | Under 50 MB each | Check byte length |
| Alpha | Mask has an alpha channel | Image mode is RGBA or LA |
Check it in Python
This reads both files and fails early. It uses only Pillow and the standard library, and it does not call Sume.
import os
from PIL import Image
def check(image_path: str, mask_path: str) -> None:
img, mask = Image.open(image_path), Image.open(mask_path)
assert img.size == mask.size, f"size {img.size} != {mask.size}"
assert img.format == mask.format, f"format {img.format} != {mask.format}"
assert "A" in mask.getbands(), "mask has no alpha channel"
for p in (image_path, mask_path):
assert os.path.getsize(p) < 50 * 1024 * 1024, f"{p} is over 50 MB"
check("room.png", "room-mask.png")
print("ok")Then host both files
The Sume rules are about URLs. Reference and mask URLs must be public HTTPS; localhost, private-network and non-HTTPS URLs are rejected before submission, per the Image API docs. The Media inputs page covers how to host a file. Then the request carries the image as an input_references entry and the mask as mask_url.
{
"model": "openai/gpt-image-2.5-sunburst",
"prompt": "Replace the masked sofa with a green velvet armchair. Leave everything else unchanged.",
"input_references": [
{"type": "image_url", "image_url": {"url": "https://example.com/room.png"}}
],
"mask_url": "https://example.com/room-mask.png",
"aspect_ratio": "auto",
"quality": "high"
}What we do not know
Which pixels in the alpha channel count as editable is a convention of the model; OpenAI's guide is the source for it, and we did not restate it here without a quote. Test with a small mask first and look at the result. On the legacy Image 1.0 route the field is mask_image_url, not mask_url, as the Image 1.0 page shows.
Sources
Related posts
More in Developers
- OpenAI Python 3.23 turn artifacts: hand over a Sume render
OpenAI Python SDK 3.23.0 adds file staging and turn artifact downloads for agents. Sume job webhooks give you a public media.sume.com URL to hand over.
- OpenAI Realtime GA migration: drop the OpenAI-Beta header
Beta Realtime integrations must move to GA and stop sending OpenAI-Beta: realtime=v1. A short checklist, a code scan for the header, and where Sume jobs fit.
- OpenAI TTS: 13 built-in voices vs 9 legacy ones, pick the model first
OpenAI's guide lists gpt-4o-mini-tts with 13 built-in voices and legacy tts-1 and tts-1-hd with 9. Formats, custom voice consent and disclosure, as a checklist.
- OpenTelemetry spans for MCP tools: tag the Sume request_id
Claude Code v2.1.283 adds MCP tool outputs to OpenTelemetry spans. Put the Sume request_id on the span and keep signed URLs off it.
Written by Sume