Fix: CocoaPods `Init_ffi_c` Symbol Not Found on Apple Silicon

Fix: CocoaPods `Init_ffi_c` Symbol Not Found on Apple Silicon

Written by

in

Quick answer: The dlsym ... Init_ffi_c LoadError means the compiled ffi_c.bundle was built for a different CPU architecture than the Ruby process running pod. Reinstall the ffi gem for the architecture you actually run (sudo arch -x86_64 gem install ffi under Rosetta, or plain sudo gem install ffi natively), or drop the gem entirely and install CocoaPods with brew install cocoapods.

Why this happens

CocoaPods is a Ruby program, and one of its dependencies (ethon, pulled in by typhoeus) needs the ffi gem. ffi is not pure Ruby: it ships a compiled C extension called ffi_c.bundle. When Ruby loads that bundle, it looks up a symbol named Init_ffi_c to register the extension. The error

LoadError - dlsym(0x7f8926035eb0, Init_ffi_c): symbol not found - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle

means dyld found the file but could not find that symbol inside it. In practice this is almost always an architecture mismatch: the bundle contains an x86_64 slice while the Ruby process is arm64, or the other way round. The wrong slice is loaded, the symbol table does not match, and the load fails.

On an Apple Silicon Mac you end up with two Ruby worlds. The system Ruby lives in /System/Library/Frameworks/Ruby.framework, but gems you install with sudo gem install land in /Library/Ruby/Gems/2.6.0. Native extensions there are compiled for whatever architecture the install process was running under. Install once under Rosetta and once natively, and you get a gem directory that no single pod invocation can satisfy.

There is a second problem: ffi 1.13.1 predates Apple Silicon, so even a clean build of that exact version can fail on arm64. Newer ffi releases handle arm64-darwin properly.

How to fix it

1. Pick one architecture and stay in it

If you want to keep using the system Ruby under Rosetta, make every step x86_64. First confirm Rosetta is installed — without it you get arch: posix_spawnp: gem: Bad CPU type in executable:

softwareupdate --install-rosetta --agree-to-license

Then rebuild the extension and run CocoaPods with the same prefix:

sudo arch -x86_64 gem install ffi
cd ios
arch -x86_64 pod install

If you type pod all day, add an alias to ~/.zshrc so you never forget the prefix:

alias pod='arch -x86_64 pod'

This is the classic workaround and it works, but it locks your whole toolchain to Rosetta. If you later open a native arm64 terminal, the error comes straight back.

2. Rebuild ffi natively instead

The simpler variant: install the gem without the arch prefix so it compiles an arm64 slice, then run pod normally.

sudo gem install ffi
cd ios
pod install

This is the fix many people land on after disabling Rosetta. It only helps if the gem actually rebuilds — if you already have a stale x86_64 build in /Library/Ruby/Gems, remove it first:

sudo gem uninstall ffi
sudo gem install ffi

Before and after, check which slice you have:

file /Library/Ruby/Gems/2.6.0/gems/ffi-*/lib/ffi_c.bundle

The output tells you x86_64 or arm64. It must match the Ruby that runs pod.

3. Install CocoaPods with Homebrew (best long-term fix)

Homebrew’s CocoaPods formula brings its own Ruby, so it never touches the system gem directory and never fights over architecture. Remove the gem version first so pod resolves to the right binary:

sudo gem uninstall cocoapods
brew install cocoapods

Then verify which binary your shell actually finds:

which -a pod
pod --version

On Apple Silicon you want /opt/homebrew/bin/pod. If /usr/local/bin/pod or /usr/bin/pod still wins, your PATH order is wrong — fix that rather than reinstalling.

4. Use a version manager if you need a specific Ruby

If your project pins a Ruby version, install it with rbenv or rvm so it is a native arm64 build, then install CocoaPods into that Ruby:

gem install cocoapods

No sudo, no arch prefix, no system gem directory. This is the cleanest setup for teams that need reproducible Ruby versions, at the cost of one more tool to manage.

5. Clean the Flutter side afterwards

A failed pod install leaves half-written state behind. Once the Ruby side is fixed, start clean:

flutter clean
rm -rf ios/Pods ios/Podfile.lock
flutter pub get
cd ios && pod install

Then build again from Xcode or with flutter run.

How to prevent it

  • Never mix sudo gem install and arch -x86_64 gem install for the same gem — pick one architecture per Ruby.
  • Prefer Homebrew or a Ruby version manager over the system Ruby; the system gem directory is shared and easy to corrupt.
  • Run which -a pod after any install so you know which binary and which Ruby you are actually using.
  • After moving a project to a new Mac, delete Pods/ and Podfile.lock and reinstall rather than copying the old build artifacts.
  • Keep ffi reasonably current; old releases have no arm64 support at all.

FAQ

Do I still need Rosetta to run CocoaPods?

No. Rosetta is only needed if you deliberately run the x86_64 toolchain. A native arm64 Ruby with a current ffi gem, or Homebrew’s CocoaPods, runs without it.

What does arch: posix_spawnp: gem: Bad CPU type in executable mean?

It means the arch -x86_64 prefix was used but Rosetta is not installed, so macOS cannot launch an Intel binary. Run softwareupdate --install-rosetta --agree-to-license and retry.

Will switching to Homebrew CocoaPods break my project?

No. The Podfile, Podfile.lock and Pods/ folder belong to the project, not to the CocoaPods installation. Only the pod executable changes, and the resolved pod versions stay the same.

Sources & credits

Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.