Platform: macOS 14.6.1 (Sonoma), Intel x86_64 · Homebrew 6.x · R 4.6.1 · sf linked to GDAL via Homebrew
If you landed here from an error like Library not loaded: libx265.216.dylib or
Symbol not found: _x265_api_get_216 when loading sf (or terra, gdal, anything
that pulls in libheif), this gist explains what happened, the fix that worked, and
the alternative approaches.
Full error I got:
library(sf) Error: package or namespace load failed for ‘sf’ in dyn.load(file, DLLpath = DLLpath, ...): unable to load shared object '/usr/local/lib/R/4.6/site-library/sf/libs/sf.so': dlopen(/usr/local/lib/R/4.6/site-library/sf/libs/sf.so, 0x0006): Library not loaded: /usr/local/opt/x265/lib/libx265.216.dylib Referenced from: <13B19319-38AC-30F1-8915-7F1DB6F58C49> /usr/local/Cellar/libheif/1.23.1/lib/libheif.1.23.1.dylib Reason: tried: '/usr/local/opt/x265/lib/libx265.216.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/local/opt/x265/lib/libx265.216.dylib' (no such file), '/usr/local/opt/x265/lib/libx265.216.dylib' (no such file), '/usr/local/Cellar/r/4.6.1/lib/R/lib/libx265.216.dylib' (no such file), '/var/folders/gt/vdp_nx_x3bq5wgnlr1nphkd1zbdps_/T/rstudio-fallback-library-path-1062076913/libx265.216.dylib' (no such file), '/usr/local/Cellar/x265/4.3/lib/libx265.216.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/local/Cellar/x265/4.3/lib/libx265.216.
Loading sf fails at dyn.load:
Error: package or namespace load failed for 'sf' in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/4.6/site-library/sf/libs/sf.so':
dlopen(.../sf.so): Library not loaded: /usr/local/opt/x265/lib/libx265.216.dylib
Referenced from: .../libheif/1.23.1/lib/libheif.1.23.1.dylib
Reason: tried: '/usr/local/opt/x265/lib/libx265.216.dylib' (no such file), ...
After a naive symlink attempt (see below), the error changes to:
Symbol not found: _x265_api_get_216
Referenced from: .../libheif/1.23.1/lib/libheif.1.23.1.dylib
Expected in: /usr/local/Cellar/x265/4.3/lib/libx265.217.dylib
The dependency chain is:
sf.so -> libheif -> libx265
- The installed libheif 1.23.1 was built against x265 API build 216. It hard-links
both the file
libx265.216.dyliband the versioned symbolx265_api_get_216. - A
brew upgradebumped x265 to 4.3, which ships onlylibx265.217.dyliband exportsx265_api_get_217. The.216file and symbol are gone. - Normally you'd just
brew reinstall libheifso it rebuilds against x265 4.3. But Homebrew dropped macOS Intel x86_64 support (announced Aug 2025, effective 2026). There are no more Intel bottles, sobrewfalls back to building from source, and theaomdependency build fails by design. Homebrew even prints: "This build failure was expected, as this is not a Tier 1 configuration."
So on an Intel Mac you cannot rebuild libheif through Homebrew, and the x265 upgrade left a version/ABI gap that breaks everything downstream of libheif.
# DON'T rely on this — it only fixes the filename, not the ABI
ln -s /usr/local/opt/x265/lib/libx265.217.dylib /usr/local/opt/x265/lib/libx265.216.dylibThis resolves the missing-file error but then fails with Symbol not found: _x265_api_get_216,
because x265 4.3 genuinely renamed the versioned entry point to x265_api_get_217. It's a real
API bump, not just a renamed file.
Restore the old x265 4.2 libx265.216.dylib and place it alongside the current 4.3 library.
libheif then loads .216; everything else keeps using .217. Both coexist because they have
different version suffixes.
# anonymous pull token
TOKEN=$(curl -s "https://ghcr.io/token?service=ghcr.io&scope=repository:homebrew/core/x265:pull" \
| sed -E 's/.*"token":"([^"]+)".*/\1/')
# find the x86_64 Sonoma manifest for tag 4.2 (annotation "4.2.sonoma")
curl -s -H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.oci.image.index.v1+json" \
https://ghcr.io/v2/homebrew/core/x265/manifests/4.2 | python3 -m json.tool | less
# -> pick the digest for "4.2.sonoma" (Intel). At time of writing:
# sha256:4b91eb72eaba279480c24aba933f36e4cd409318d627212f5812d91320050df1Adjust the platform tag to match your macOS:
sonoma(14, x86_64),ventura,monterey, or thearm64_*variants on Apple Silicon. Digests will differ over time — always read them from the manifest rather than copying the one above.
MAN=sha256:4b91eb72eaba279480c24aba933f36e4cd409318d627212f5812d91320050df1
# get the single layer (the bottle tarball) blob digest
BLOB=$(curl -s -H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.oci.image.manifest.v1+json" \
https://ghcr.io/v2/homebrew/core/x265/manifests/$MAN \
| python3 -c "import sys,json;print(json.load(sys.stdin)['layers'][0]['digest'])")
# download the bottle
curl -s -L -H "Authorization: Bearer $TOKEN" \
"https://ghcr.io/v2/homebrew/core/x265/blobs/$BLOB" -o /tmp/x265-4.2.tar.gzmkdir -p /tmp/x265extract
tar xzf /tmp/x265-4.2.tar.gz -C /tmp/x265extract x265/4.2/lib/libx265.216.dylib
# sanity check: it exports the symbol libheif needs
nm -gU /tmp/x265extract/x265/4.2/lib/libx265.216.dylib | grep _x265_api_get_216
# place it next to the current 4.3 library
cp /tmp/x265extract/x265/4.2/lib/libx265.216.dylib \
/usr/local/Cellar/x265/4.3/lib/libx265.216.dylibbrew pin x265library(sf)
sf::sf_extSoftVersion()
#> Linking to GEOS 3.14.1, GDAL 3.13.2, PROJ 9.8.1; sf_use_s2() is TRUEDone. sf loads again.
Caveats: this is a coexistence hack. If you later brew reinstall x265 or an upgrade touches
libheif/gdal, the manually placed .216 dylib may be removed and you'll need to repeat it.
| Approach | Effort | Durability | Notes |
|---|---|---|---|
Drop in old libx265.216.dylib + brew pin x265 (this gist) |
Low | Medium | Fastest unblock; survives until something rebuilds the chain |
| Downgrade the whole x265 formula to 4.2 | Low–Med | Medium | Same idea, coarser; affects every x265 consumer |
| Reinstall/rebuild libheif against x265 4.3 | — | — | The "correct" fix, but not possible via Homebrew on Intel (source build of aom fails) |
| Migrate the geospatial stack to conda-forge | Medium | High | Recommended long-term on Intel; see below |
| Migrate Homebrew stack to MacPorts | High | High | Homebrew's own suggested route for Intel |
| Move to Apple Silicon / Docker / Linux | High | High | Sidesteps the dropped-platform problem entirely |
Install R and r-sf and the C libraries together so everything links against conda-forge:
# Miniforge (conda-forge by default), Intel build
curl -L -o /tmp/miniforge.sh \
https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-x86_64.sh
bash /tmp/miniforge.sh -b -p "$HOME/miniforge3"
source "$HOME/miniforge3/etc/profile.d/conda.sh"
conda create -n geo -c conda-forge \
r-base r-sf r-terra r-stars r-tidyverse \
gdal geos proj
conda activate geoThen point RStudio at ~/miniforge3/envs/geo/bin/R
(Tools → Global Options → General → R version → Change) and restart.
Keep GDAL-dependent R packages coming from conda-forge (conda install -c conda-forge r-<pkg>)
rather than install.packages(), to avoid relinking against the wrong system libraries.
sf broke because a Homebrew x265 upgrade (4.2 → 4.3, API build 216 → 217) left libheif
pointing at a libx265.216.dylib / x265_api_get_216 that no longer exist, and Homebrew can't
rebuild libheif on Intel macOS anymore. Fix: fetch the old x265 4.2 libx265.216.dylib from
ghcr, place it next to the 4.3 library, and brew pin x265. For a durable setup on Intel, move
the geospatial stack to conda-forge.