DEV Community

Jackson
Jackson

Posted on Originally published at macless.dev

Fix ITMS-90035: "Invalid Signature. A sealed resource is missing or invalid"

Upload finishes, then the rejection email arrives:

ERROR ITMS-90035: "Invalid Signature. A sealed resource is
missing or invalid. The file at path [MyApp.app/Frameworks/
SomeSDK.framework/SomeSDK] is not properly signed."
Enter fullscreen mode Exit fullscreen mode

The headline sends people off to check their distribution certificate, regenerate a provisioning profile, and upload the same broken binary again. Your app signature is usually fine. Something inside the app bundle is not. The bracketed path names it exactly, and that path is the only part of the message worth reading first.

What "sealed resource" means

When you sign a bundle, codesign records a hash of everything inside it. That set of hashes is the seal. At upload, Apple recomputes it. If any file inside the bundle is missing, added, altered, or itself an unsigned piece of code, the recomputed seal no longer matches and the whole thing is rejected. So the error fires for two different situations that need opposite fixes: something inside was never signed, or something inside changed after signing.

Check the path it named

Unzip the exact .ipa you uploaded and look at the offending item directly:

unzip -q MyApp.ipa -d out
codesign -dv --verbose=4 out/Payload/MyApp.app/Frameworks/SomeSDK.framework
Enter fullscreen mode Exit fullscreen mode

code object is not signed at all means nothing signed it. An Authority line naming a different team or a development certificate means it was signed, with the wrong identity.

Then verify the whole bundle the way Apple does:

codesign --verify --deep --strict --verbose=2 out/Payload/MyApp.app
Enter fullscreen mode Exit fullscreen mode

Run this on the archive before you upload, not after the rejection. It catches the same problem in a few seconds instead of an hour.

Cause 1: a framework nothing is signing

A third-party framework or .dylib that gets copied into the bundle by a Copy Files build phase never gets signed, because copying is not embedding. Frameworks have to be listed under Embed & Sign in the target's General tab. If a framework is set to Do Not Embed and a script drops it in anyway, the app signs cleanly and the framework inside it does not.

The same applies to anything nested deeper. A binary framework that ships its own bundled dylibs can leave those unsigned even when the outer framework is embedded correctly, which is why the path in the error is sometimes several levels down.

Cause 2: something touched the bundle after signing

This is the CI version, and it is almost always ordering. Signing happens during xcodebuild -exportArchive. Any step that writes into the .app after that point breaks the seal, even if the change looks harmless. Copying in a config file, swapping an icon, patching an Info.plist value, rewriting a build number, all of it.

The fix is order, not re-signing. Make the modification before the export step, so the signature is computed over the final contents. If a pipeline genuinely has to alter the app afterwards, it has to re-sign afterwards too, and that is a worse pipeline.

Cause 3: files that should not be in there

Stray files inside the bundle can invalidate the seal on their own. Extended attributes and resource forks picked up from macOS are the common ones, along with .DS_Store files that get swept in by an overly broad copy phase. Clear them before archiving:

xattr -cr path/to/MyApp.app
Enter fullscreen mode Exit fullscreen mode

Also check that no build phase is copying an entire source directory into the bundle. If a copy phase uses a wildcard, it will happily include things you never meant to ship.

Why "just re-sign with --deep" is bad advice

It shows up in every thread about this error, and it does sometimes make the upload go through. Apple's own guidance is against it. --deep re-signs everything inside the bundle with your identity, including code that was signed by someone else for a reason, and it papers over a build configuration that is still wrong. The next SDK update brings the error straight back. Fix the embed setting or the phase order instead.

Top comments (0)