How to Fix Mach-O Header Code 0x72613c21 When You Try to Export Your App in Xcode

I was preparing a test build to check if linking against a new library worked fine in production. Trying to distribute the app using my Developer ID (but this would also have happened in a step before uploading to the App Store), I got this:

Found an unexpected Mach-O header code: 0x72613c21

Oops?

Like probably most developers, I have absolutely no clue about many crucial steps in the app making process. Especially stuff like code signing and most build settings elude me – I pick up pieces over the years, but not with the same speed with which I’m getting better at writing apps. So I didn’t understand what’s going on at all here. The search results I got weren’t that useful, so this post is meant to fill the vacuum for the next person running into this.

Didn't hurt to also make a video demo if you don't know where to click

Code 0x72613c212 Indicates You Are Embedding a Static Library

As far as I understand the message, embedding a static library in your app binary can produce code 0x72613c21. There may be other causes. But in short, this was the issue for me.

My app bundle is embedding a .framework bundle which in turn embeds a 3rd party library. The first embedding step is fine. The second isn’t, because the 3rd party library is a static library. I didn’t pay attention to this because I had no clue this is a problem in the first place.

An Apple Technical Note, TN2435, has an explanation for this. It’s a good resource, but it wasn’t among the first suggestions of my initial search; it did pop up when I asked the search engine why not embed static libraries xcode, though:

The following error indicates your app embedded a static library.

Found an unexpected Mach-O header code: 0x72613c21

This is caused by placing a static library in a bundle structure that looks like a framework; this packaging is sometimes referred to by third party framework developers as a static framework. Since the binary in these situations is a static library, apps cannot embed it in the app bundle.

How to Check If a Binary Is a Static Library

If you’re not sure if you have a static or dynamic library, TN2435 even includes instructions to check:

Terminal command to determine if a binary is a static library

file <PathToAppFramework>/<FrameworkName>.framework/<FrameworkName>

Example output for a static library

Mach-O universal binary with 2 architectures

<PathToLibrary> (for architecture armv7): current ar archive random library

<PathToLibrary> (for architecture arm64): current ar archive random library

I checked, and sure enough, this is the truncated output. Looks similar:

.../Versions/a/libMultiMarkdown: Mach-O universal binary with 2 architectures:
    [arm64:current ar archive random library] [x86_64:current ar archive random library]
.../Versions/A/libMultiMarkdown (for architecture arm64):
    current ar archive random library
.../Versions/A/libMultiMarkdown (for architecture x86_64):
    current ar archive random library

Compare this to a regular framework built in Swift:

.../Versions/A/JSONAttachment: Mach-O universal binary with 2 architectures:
    [x86_64:Mach-O 64-bit dynamically linked shared library x86_64]
    [arm64:Mach-O 64-bit dynamically linked shared library arm64]
.../Versions/A/JSONAttachment (for architecture x86_64):
    Mach-O 64-bit dynamically linked shared library x86_64
.../Versions/A/JSONAttachment (for architecture arm64):
    Mach-O 64-bit dynamically linked shared library arm64

There, you see “dynamically linked”, so conversely, the other isn’t.

This TN2435 I have just found when I wanted to look for more references for my own notes. I didn’t know about this yesterday when I ran into the problem. Most search results I found suggested using otool -h and otool -f instead. But I could not make sense of the results at all. And for the library in question, the static lib appeared to be the concatenated result of many .o files, so the output was crazy long, too.

Instead of even bothering with otool for library inspection, just check the binary product with file instead.

Fix: Do Not Embed Static Libraries

The solution, also mentioned in TN2435, is a simple change:

Once you’ve confirmed the library is static, go to the Build Phases for the app target in Xcode. Remove this library from any build phase named “Copy Files” or “Embed Frameworks.” The library should remain in the “Link Binary with Libraries” section.

By default, when you add a library to a framework or app target, Xcode chooses “Embed & Sign”. Was
the case for me as well here.

Change the library setting to 'Do Not Embed'

Change that to “Do Not Embed”, and you’re golden.

The result is that the framework is removed from the 'Embed Frameworks' build phase, but not the 'Link Binary With Libraries' phase; you can also perform this step manually, esp. if your Xcode version doesn't show the convenient 'Do Not Embed' dropdown

See also: