Question

Fixing dyld Library Not Loaded Errors for PHP on macOS Homebrew

phpnode.jsmacoshomebrew

Question

I installed Node.js using Homebrew on macOS Mojave. After that, PHP stopped working. When I run the following command:

php -v

I get this error:

dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib
  Referenced from: /usr/local/bin/php
  Reason: image not found

I also tried uninstalling both node and icu4c, but the problem still remains. What causes this error, and how can I fix PHP so it works again?

Short Answer

By the end of this page, you will understand what a dyld: Library not loaded error means on macOS, why Homebrew package upgrades can break PHP, how shared libraries like icu4c are linked, and the practical steps to diagnose and repair broken Homebrew installations.

Concept

On macOS, many programs do not contain every piece of code they need inside a single executable file. Instead, they depend on shared libraries at runtime. When you run a command like php -v, macOS uses the dynamic loader (dyld) to find and load the libraries PHP was built against.

In this case, PHP is trying to load this file:

/usr/local/opt/icu4c/lib/libicui18n.62.dylib

That file belongs to the Homebrew package icu4c, which provides ICU libraries used for Unicode and internationalization features.

The error happens because PHP was built or linked against a specific ICU version (62), but that exact file no longer exists. This often happens when:

  • Homebrew upgrades icu4c to a newer version
  • A package was removed or relinked
  • PHP still points to an older library path
  • Homebrew dependencies became inconsistent after installing or upgrading another package

This matters because many command-line tools and server applications depend on shared libraries. If dependency versions move but binaries are not rebuilt, programs can stop working even though the program itself was not directly changed.

The core idea is:

  • Your PHP binary is fine as a file
  • Its runtime dependency link is broken
  • The fix is usually to reinstall or relink the dependency or rebuild PHP against the current library version

Mental Model

Think of PHP as a worker showing up to do a job with a list of helper tools it expects to find in a toolbox.

  • PHP = the worker
  • dyld = the person checking the toolbox before work starts
  • icu4c library file = one of the required tools

If the worker says, "I need tool version 62," but the toolbox only contains version 63 or 64, work cannot start.

So the problem is not that the worker disappeared. The problem is that the exact helper tool PHP expects is missing.

In Homebrew terms:

  • Homebrew installs and upgrades packages
  • Some packages depend on others
  • If one dependency changes version, the dependent package may need to be rebuilt or reinstalled
Take Quiz

Syntax and Examples

The most useful commands here are diagnostic shell commands.

Check which PHP is being used

which php
php -v

This tells you the binary path and whether it starts correctly.

Inspect Homebrew package status

brew list --versions php icu4c node
brew info php
brew info icu4c

This shows which versions are installed and whether Homebrew still knows about them.

Reinstall the missing dependency and PHP

brew reinstall icu4c
brew reinstall php

This is the most common fix because it ensures:

  • icu4c is present
  • PHP is rebuilt or relinked against the current ICU library version

Refresh Homebrew metadata first

brew update
brew upgrade
brew reinstall php

Use this if your Homebrew state is old or inconsistent.

Example repair workflow

brew update
brew reinstall icu4c
brew reinstall php
php -v

If successful, php -v should print the PHP version instead of the dyld error.

If the wrong PHP binary is being used

Sometimes /usr/local/bin/php points to an outdated binary.

which php
ls -l /usr/local/bin/php

If needed, relink Homebrew's PHP:

brew unlink php
brew link php --overwrite --force

Use force options carefully, because they can replace symlinks for conflicting files.

Step by Step Execution

Consider this command sequence:

brew reinstall icu4c
brew reinstall php
php -v

Here is what happens step by step:

  1. brew reinstall icu4c

    • Homebrew downloads or uses a cached copy of the icu4c package.
    • It installs the current ICU libraries under the Homebrew Cellar.
    • It updates the opt symlink so packages can refer to the active version.
  2. brew reinstall php

    • Homebrew reinstalls PHP.
    • During installation, PHP is linked against the currently installed icu4c version.
    • Symlinks such as /usr/local/bin/php are updated.
  3. php -v

    • The shell finds the php executable.
    • macOS runs dyld to load all shared libraries PHP needs.
    • Because the expected ICU library is now available and correctly linked, PHP starts normally.

Small trace example

Broken state:

php -v

Result:

dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib

After reinstall:

brew reinstall icu4c
brew reinstall php
php -v

Result:

PHP 8.x.x (cli) ...

That change tells you the issue was not PHP syntax or your code. It was runtime linking.

Real World Use Cases

This concept appears often in real development environments.

Local development setups

You install or upgrade one tool with Homebrew, and another tool breaks because both share dependencies.

Examples:

  • PHP breaks after icu4c changes
  • Python packages fail after OpenSSL upgrades
  • Database clients stop working after library updates

CI and build servers

A build image updates system packages, but cached binaries still expect old shared libraries.

Native extensions

Language runtimes such as PHP, Python, Ruby, and Node may use compiled extensions that depend on system libraries.

Command-line tools

Utilities installed with package managers often depend on dynamic libraries. A missing version can prevent the tool from launching at all.

Web server environments

If Apache, Nginx helpers, or PHP-FPM are linked against outdated libraries, local or staging servers may fail to start.

Take Quiz

Real Codebase Usage

In real projects, developers usually handle this kind of issue with repeatable environment management rather than one-off fixes.

Common patterns

Reinstall after dependency upgrades

If a shared library changes, reinstall dependent packages:

brew reinstall php
brew reinstall wget
brew reinstall imagemagick

Verify the active binary

Developers often check for path issues before debugging deeper:

which php
which node
which python3

This helps detect when an old binary is still first in PATH.

Use guard checks in setup scripts

Teams often include validation commands in onboarding scripts:

php -v || echo "PHP is broken"
brew doctor

Keep package manager state healthy

Useful maintenance commands:

brew update
brew doctor
brew cleanup

Prefer reproducible environments

In larger codebases, developers may avoid system dependency drift by using:

  • Docker containers
  • Version managers
  • Project-specific setup scripts
  • CI images pinned to known versions

This reduces the chance that a Homebrew upgrade breaks unrelated tools.

Common Mistakes

1. Reinstalling the wrong package only

A common mistake is reinstalling node because the problem appeared after installing Node.js.

brew reinstall node

That may not help, because the broken package is actually PHP or one of PHP's dependencies.

Better approach

Reinstall the dependency and the dependent package:

brew reinstall icu4c
brew reinstall php

2. Assuming uninstalling fixes broken links

Removing packages can make the situation worse if another package still depends on them.

Broken approach:

brew uninstall icu4c

If PHP still expects icu4c, uninstalling it guarantees PHP cannot start.

3. Ignoring which binary is actually running

You may have multiple PHP installations.

which php

If this points to an old binary, reinstalling another PHP may not solve the issue.

4. Manually creating fake library files

Some users try to hack around the problem with manual symlinks from one version to another.

Example of a risky workaround:

ln -s /usr/local/opt/icu4c/lib/libicui18n.64.dylib /usr/local/opt/icu4c/lib/libicui18n.62.dylib

This can break in subtle ways because different library versions are not guaranteed to be compatible.

5. Skipping Homebrew health checks

If Homebrew itself is in a bad state, reinstalling may not be enough.

Use:

brew doctor

6. Forgetting to update shell paths

If you changed shell configuration or migrated between Intel and Apple Silicon setups, your shell may still point to outdated locations.

Comparisons

ApproachWhat it doesWhen to use itRisk level
brew reinstall icu4cReinstalls the missing libraryWhen the library package is missing or corruptedLow
brew reinstall phpRebuilds or relinks PHP against current dependenciesWhen PHP references an old library versionLow
brew unlink php && brew link php --forceRefreshes Homebrew symlinksWhen the installed PHP is correct but symlinks are staleMedium
Manual symlink hackPretends one library version is anotherOnly as a temporary emergency workaround, if everHigh
Uninstall random packagesRemoves software without fixing linksUsually not recommendedHigh

Reinstall vs relink

ActionPurpose
ReinstallRecreates files and dependencies cleanly
RelinkFixes symlinks to already installed files

If files are missing, reinstall is usually better than relink.

Homebrew PHP vs system PHP

Version sourceTypical pathNotes
Homebrew PHP/usr/local/bin/php or /opt/homebrew/bin/phpDepends on Homebrew libraries
System PHP/usr/bin/phpMay be older and managed by macOS

Knowing which one you are using is important before fixing the issue.

Take Quiz

Cheat Sheet

Quick diagnosis

which php
php -v
brew list --versions php icu4c
brew info php
brew info icu4c
brew doctor

Most common fix

brew update
brew reinstall icu4c
brew reinstall php
php -v

Refresh symlinks

brew unlink php
brew link php --overwrite --force

Useful ideas to remember

  • dyld is macOS's dynamic loader
  • .dylib files are dynamic libraries
  • icu4c provides ICU Unicode/internationalization libraries
  • A missing versioned library usually means a package upgrade changed the dependency version
  • Reinstalling the dependent package is often necessary after a dependency upgrade
  • Check which php before assuming the correct binary is being used

Red flags

  • Manually faking library versions with symlinks
  • Uninstalling dependencies without checking what uses them
  • Assuming the last package you installed is the package that is broken

FAQ

Why did PHP break after installing Node with Homebrew?

Installing Node may have triggered Homebrew to upgrade or relink shared dependencies. PHP then tried to load an older ICU library version that no longer existed.

What does dyld: Library not loaded mean on macOS?

It means the executable started, but macOS could not find one of the shared libraries it needs at runtime.

What is icu4c used for?

icu4c provides ICU libraries for Unicode, locales, collation, and other internationalization features used by many programs, including PHP.

Is uninstalling icu4c a good fix?

Usually no. If PHP depends on it, removing it will not solve the problem. Reinstalling it and PHP is a better approach.

How do I know if I have multiple PHP versions installed?

Run:

which php
ls -l $(which php)

This shows which binary your shell is using.

Should I manually create a symlink from a newer ICU version to the missing one?

Usually no. Library versions may not be binary compatible, so this can cause crashes or harder-to-debug errors.

What command usually fixes this fastest?

In most cases:

brew update
brew reinstall icu4c
brew reinstall php

What if reinstalling PHP still does not work?

Check brew doctor, verify your PATH, inspect which PHP binary is being used, and confirm that no older manual installation is shadowing Homebrew's PHP.

Take Quiz

Mini Project

Description

Create a small shell-based troubleshooting checklist for diagnosing broken Homebrew runtime dependencies on macOS. This project helps you practice the exact commands developers use when tools like PHP fail because of missing shared libraries.

Goal

Build and run a short diagnostic workflow that identifies the active PHP binary, checks Homebrew package state, and repairs a broken PHP installation.

Requirements

  • Check which php binary is currently being used.
  • Verify whether php and icu4c are installed by Homebrew.
  • Run a Homebrew health check.
  • Reinstall the dependency and PHP.
  • Confirm that php -v works after the repair.
Take Quiz

Keep learning

Related questions

View more