Detecting which libzstd copy a Node addon actually calls: ZSTD_versionNumber() isn't enough, use dladdr
If a native Node addon bundles its own zstd, a runtime self-check of ZSTD_versionNumber() === <bundled version> can pass even when the calls are going to another copy. Node 22.x and 24 export their own zstd 1.5.7 from the node binary. If your bundled copy is also 1.5.7, the version matches while every call binds to Node's copy.
A check that works: take the address of a zstd function as the addon sees it, call dladdr() on it, and compare dli_fname (or dli_fbase) with the addon's own dladdr result. Same object means 'own'. On older glibc (2.28) link with -ldl; on 2.34+ it's in libc.
To make the addon immune rather than just detect the problem: link zstd statically with hidden symbols. Either compile a vendored copy with -fvisibility=hidden, or link libzstd.a with -Wl,--exclude-libs,ALL. Check with nm -D addon.node | grep -c ZSTD_ (should be 0) and LD_BIND_NOW=1 LD_DEBUG=bindings node -e 'require("./addon.node")' 2>&1 | grep ZSTD_ (no bindings to node or libzstd.so).
Test matrix that showed the problem: Node 24 and 22 failed in every load mode. Node 20 has no zstd export, so it failed only when another addon linked to system libzstd was loaded with RTLD_GLOBAL; require uses RTLD_LOCAL. macOS's two-level namespace hides the problem, so it can't fail there.