If you run Ansible on macOS and see a crash about +[__NSCFConstantString initialize] and fork(), this is a known conflict between Python's multiprocessing, Ansible's forking behavior, and macOS's Objective-C runtime safety checks. Here's exactly what causes it and how to fix it.

The Error

objc[22868]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called.
objc[22868]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.

Root Cause

Starting with macOS High Sierra (10.13), Apple added a safety check in the Objective-C runtime that crashes any process that calls fork() without immediately calling exec() if Objective-C classes are being initialized in another thread.

Ansible uses Python's multiprocessing module to fork child processes for parallel task execution. When Python forks on macOS, the child process inherits the parent's memory — including partially-initialized Objective-C classes. macOS detects this as unsafe and kills the process.

This affects:

  • Ansible with forks > 1 (the default is 5)
  • Any Python script that uses multiprocessing or os.fork() on macOS
  • All macOS versions from High Sierra onward (including Ventura, Sonoma, Sequoia)

Current Terminal Session Only

export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
ansible-playbook site.yml

Permanent Fix (All Sessions)

Add to your shell profile:

# For bash
echo 'export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES' >> ~/.bash_profile

# For zsh (default on modern macOS)
echo 'export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES' >> ~/.zshrc

# For fish
set -Ux OBJC_DISABLE_INITIALIZE_FORK_SAFETY YES

Verify It's Set

env | grep OBJC
# Should show: OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

Fix 2: Reduce Forks to 1

If you prefer not to disable the safety check:

# ansible.cfg
[defaults]
forks = 1

Or per-command:

ansible-playbook site.yml -f 1

This eliminates forking entirely but runs tasks sequentially (slower for multi-host playbooks).

Fix 3: Use a Python Virtual Environment

Sometimes the issue is triggered by system Python interacting with macOS frameworks:

# Create a clean venv
python3 -m venv ~/ansible-venv
source ~/ansible-venv/bin/activate
pip install ansible

# Run Ansible from the venv
ansible-playbook site.yml

Virtual environments can reduce (but not always eliminate) the fork conflict.

Fix 4: Run Ansible in a Container

Avoid macOS fork issues entirely by running Ansible in Docker:

docker run --rm -it \
  -v $(pwd):/ansible \
  -v ~/.ssh:/root/.ssh:ro \
  -w /ansible \
  python:3.12-slim \
  bash -c "pip install ansible && ansible-playbook site.yml"

Or use the official Ansible execution environment:

pip install ansible-navigator
ansible-navigator run site.yml --mode stdout

Which Fix Should You Use?

FixProsCons
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YESSimple, one line, keeps parallel executionDisables a macOS safety check
forks = 1No env changes neededVery slow for multi-host playbooks
Virtual environmentCleaner Python setupDoesn't always fix the issue
Docker/containerComplete isolationMore complex setup

For most users, Fix 1 (environment variable) is the right answer. The safety check protects against a theoretical crash in Objective-C class initialization after fork — which doesn't affect Ansible's actual behavior. Disabling it is safe for Ansible usage.

Affected macOS Versions

macOS VersionAffected?
High Sierra (10.13)✅ First version with this check
Mojave (10.14)✅
Catalina (10.15)✅
Big Sur (11)✅
Monterey (12)✅
Ventura (13)✅
Sonoma (14)✅
Sequoia (15)✅

Conclusion

The macOS fork error is a well-known Ansible issue with a simple fix: export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES in your shell profile. This is safe for Ansible usage and preserves parallel task execution. Add it once to ~/.zshrc and forget about it.