I once laid out six 1024px PNGs side by side to find out which ones App Store Connect would turn away. One had a filled background. One had rounded corners. One was grayscale, and one had its palette reduced. Looking at them, none of them was see-through.
Yet the validation can still come back with this:
ITMS-90717: Invalid large app icon. The large app icon in the asset catalog in "___.app" can't be transparent or contain an alpha channel."Can't be transparent" and "can't contain an alpha channel" sound like the same rule. They aren't. This post checks the difference on sample files and ends with a check you can run before every upload.
The thing I'd like you to take away first: an icon that looks opaque tells you nothing about whether it is safe.
What the symptom looks like
ITMS-90717 shows up during validation when you upload a build, or in the message that follows processing. The core phrase is "can't be transparent or contain an alpha channel."
Other problems get mistaken for it. This table helps you place your own message.
| What you see | Covered here? | Look at first |
|---|---|---|
| Invalid large app icon … can't be transparent or contain an alpha channel | Yes | The 1024px icon PNG (is there an alpha channel?) |
| Build stuck on "Processing" | Different post | Processing queue, build number, email |
| Changed the icon but the old one still shows | Different symptom | Caches, assets that weren't replaced |
| Android notification icon is a white square | Different symptom | How the monochrome notification icon is made |
If you're unsure whether it's the "Processing" case, start with this walkthrough for builds stuck in processing.
I had misread the rule
Expo's documentation says the iOS icon should fill the whole square, with no rounded corners and no transparent pixels. The OS applies its own mask, so you don't round anything yourself.
For a long time I read that as "it's fine if it doesn't look see-through." That was the misreading. The error message names two conditions on purpose: not transparent, and no alpha channel.
If every pixel is fully opaque but the file is still RGBA, the alpha channel exists. You can't tell by eye.
What I measured: six sample files
I made six 1024px samples and read each PNG's IHDR header to see how it stores color. Python 3's standard library was enough.
| Sample | Looks like | Check result |
|---|---|---|
| RGB (no alpha) | Opaque | Pass |
| RGBA, every pixel opaque | Opaque (identical to the RGB one) | Fail: has an alpha channel |
| RGBA, rounded corners made transparent | Corners show through | Fail: has an alpha channel |
| Grayscale + alpha | Opaque | Fail: has an alpha channel |
| Palette PNG with transparency | Looks opaque | Fail: tRNS present |
| RGB, but 1000×1000 | Opaque | Fail: wrong size |
The second row is the point. The minimum and maximum of the alpha channel were both 255, so no pixel is see-through. The file is still RGBA, and it still carries the channel.
One limit on all this: the check only tells you what is inside the file. I did not submit these six to App Store Connect to see whether each is accepted. The Apple-side verdict rests on the wording of the error and on public forum reports.
The order I'd check causes in
- Is the exported PNG RGBA? Many design tools export RGBA by default. A painted background doesn't remove the channel.
- Did you bake rounded corners in? The corners become transparent. Hand over a plain square and let the OS do the rounding.
- Is it exactly 1024×1024? Off-by-a-little sizes like 1000px or 1024×1023 turn up late.
- Are you using an Icon Composer
.icon? Apple's developer forums have several reports from the Xcode 26 beta period of PNGs generated from Icon Composer icons containing alpha. One poster narrowed it to a group with Blur on and an SVG near the canvas edge. An Apple engineer said they were investigating, and reports differed from one build to the next. - Is the build stale? If you fixed the image and get the same error, suspect old assets.
Steps 1 to 3 can be settled with one file. Step 4 depends on the tool you export from.
The checker
It takes one or many files and reads only the PNG header, so it never opens the image.
#!/usr/bin/env python3
"""Check App Store icon PNGs before upload (standard library only).
Usage: python3 icon_alpha_check.py icon.png [more.png ...]
Exit code: 0 = all pass / 1 = at least one needs work
"""
import struct, sys
COLOR = {0: "gray", 2: "RGB", 3: "palette", 4: "gray+alpha", 6: "RGBA"}
def inspect(path):
with open(path, "rb") as f:
data = f.read()
if data[:8] != b"\x89PNG\r\n\x1a\n":
return None, ["not a PNG"]
pos, width, height, ctype, has_trns = 8, 0, 0, -1, False
while pos + 8 <= len(data):
length, kind = struct.unpack(">I4s", data[pos:pos + 8])
body = data[pos + 8:pos + 8 + length]
if kind == b"IHDR":
width, height, _depth, ctype = struct.unpack(">IIBB", body[:10])
elif kind == b"tRNS":
has_trns = True
pos += 12 + length
problems = []
if (width, height) != (1024, 1024):
problems.append(f"size is {width}x{height} (need 1024x1024)")
if ctype in (4, 6):
problems.append(f"has an alpha channel ({COLOR[ctype]})")
if ctype == 3 and has_trns:
problems.append("palette PNG with transparency (tRNS)")
return (width, height, COLOR.get(ctype, str(ctype))), problems
def main(paths):
bad = 0
for p in paths:
info, problems = inspect(p)
if problems:
bad += 1
print(f"NG {p}: " + " / ".join(problems))
else:
print(f"OK {p}: {info[0]}x{info[1]} {info[2]}")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]) if len(sys.argv) > 1 else 2)On my six samples it printed:
OK a_rgb.png: 1024x1024 RGB
NG b_rgba_opaque.png: has an alpha channel (RGBA)
NG c_rgba_rounded.png: has an alpha channel (RGBA)
NG d_la.png: has an alpha channel (gray+alpha)
NG e_palette_trns.png: palette PNG with transparency (tRNS)
NG f_rgb_1000.png: size is 1000x1000 (need 1024x1024)Because it returns an exit code, it drops straight into a pre-submit step. One NG means no upload — that's the line I draw.
The fix: remove alpha and save as RGB
Decide what color fills the transparent areas first. An icon with baked-in rounded corners has transparent corners, so they need a background color.
#!/usr/bin/env python3
"""Write an RGB PNG with the alpha channel removed.
Usage: python3 icon_flatten.py in.png out.png [#RRGGBB]
"""
import sys
from PIL import Image # pip install pillow
src, dst = sys.argv[1], sys.argv[2]
bg = sys.argv[3] if len(sys.argv) > 3 else "#FFFFFF"
bg_rgb = tuple(int(bg.lstrip("#")[i:i + 2], 16) for i in (0, 2, 4))
im = Image.open(src).convert("RGBA")
flat = Image.new("RGB", im.size, bg_rgb)
flat.paste(im, mask=im.getchannel("A"))
flat.save(dst, "PNG")
print(f"{dst}: {flat.mode} {flat.size}")Running the opaque RGBA sample through it gave an image with zero pixel difference from the original RGB sample — the difference bounding box came back empty (None). The picture is unchanged and only the channel is gone.
The rounded-corner sample comes out as a plain square with the corners filled. Since the OS rounds the corners itself, nothing visible is lost.
If you use ImageMagick, one line does the same:
convert icon.png -background "#FAFAFA" -alpha remove -alpha off PNG24:icon_fixed.pngI tripped on one thing here. My first run omitted PNG24:. The alpha was gone, but the output was a palette PNG (indexed color, 256 colors or fewer). On an icon with gradients that can make the colors look rough. With PNG24: the output was a plain RGB PNG.
If it still fails
If the script says OK and the same error keeps coming, check these in order:
- Did you actually upload the fixed file, or the old build? Bump the build number and upload again.
- Does the asset catalog hold more than one 1024px PNG? The older one may be the one being checked.
- If you use an Icon Composer
.icon, the forum reports mention turning Blur off, going back to a plain PNG, or stripping alpha from the exported PNG. Each gives up some of the visual effect, and reports varied by build, so it's worth checking whether the latest Xcode still reproduces it before changing anything.
I haven't verified how Rork's icon settings or export behave for this case, so I'm not describing them here. Please check the screens and names in your own environment.
Making it a habit
Judge transparency with your eyes, and the alpha channel with the bytes. That's the line I keep before every submission.
As an indie developer, I find the day I touch the icon and the day I submit are often far apart. An image exported a few days earlier gets a glance — "looks fine" — on submit day. I'd rather hand that glance to a script that takes seconds.
After the icon, the next thing worth checking before submit is whether a secret value has slipped into the app. I wrote up how EAS secrets and public variables differ along two axes, if you'd like to read on.
For today, run one 1024px PNG you already have through icon_alpha_check.py. That's all.