Skip to content
ohsudo, Home
Linux

"error while loading shared libraries" and "GLIBC_2.xx not found": what the loader is telling you

Fix Linux "error while loading shared libraries: cannot open shared object file" and "version GLIBC_2.xx not found": use ldd, install the library, run ldconfig, rebuild.

Intermediate5 min readApplies to Ubuntu · Debian · RHEL / Rocky / AlmaLinux · Docker

by OhSudo ··

Checked on real software: Debian, Ubuntu, Rocky Linux · November 2026How we check

Two errors from the same part of Linux. The first:

./app: error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory

The second:

./app: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by ./app)

Most programs don’t contain all their code, and at start the dynamic loader brings in the libraries they need. The first message means it can’t find a library. The second means it found one, and that one’s too old for this program.

They need different fixes. The first is usually a package to install. The second means the program was built on a newer system than yours, and installing packages won’t solve it.

  1. The programneeds libssl.so.3, GLIBC_2.38
  2. Dynamic loadersearches the library paths
  3. Missing, or too oldcannot open shared object / version not found(breaks here)
At start, the dynamic loader brings in the libraries a program needs. Either it can't find one, or the one it finds is older than the program was built for.

TL;DR

Terminal window
ldd ./app | grep 'not found' # what's missing?
apt-file search libssl.so.3 # Debian / Ubuntu: which package?
dnf provides '*/libssl.so.3' # RHEL
sudo ldconfig # after installing a library by hand

For GLIBC_2.xx: run it on a system that new, in a container, or build it on the oldest system you support.

1. See everything that’s missing

Terminal window
ldd ./app
linux-vdso.so.1 (0x00007ffd...)
libssl.so.3 => not found
libcrypto.so.3 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f...)

The loader stops at the first one it misses, and ldd shows them all. Don’t use ldd on a program you don’t trust, because it can run its code. objdump -p ./app | grep NEEDED is safe.

2. Install the package

Find which package has that file:

Terminal window
# Debian / Ubuntu
sudo apt install apt-file && sudo apt-file update
apt-file search libssl.so.3
# RHEL / Rocky / AlmaLinux
dnf provides '*/libssl.so.3'

Then install it. Some usual ones:

Library Debian / Ubuntu RHEL
libssl.so.3 libssl3t64 or libssl3 openssl-libs
libstdc++.so.6 libstdc++6 libstdc++
libz.so.1 zlib1g zlib
libpq.so.5 libpq5 libpq
libmysqlclient.so.21 libmysqlclient21 mysql-libs

Names vary by release, which is why you should search. A library with -dev or -devel is for compiling: you don’t need it just to run a program.

3. An old version number

The number at the end is the point here. libssl.so.1.1 isn’t libssl.so.3, and they’re not compatible. A program built for OpenSSL 1.1 needs exactly that, and your new system ships only 3:

libssl.so.1.1: cannot open shared object file

The clean ways out are to get a build for your release, or run the old program in a container with the older system.

Don’t make a link from the new name to the old one, as forums often suggest:

Terminal window
sudo ln -s libssl.so.3 libssl.so.1.1 # don't

The two versions aren’t compatible, and the program may start, then crash, or misbehave without an error, in code that handles your encryption.

4. It’s installed, and still not found

The loader looks in a cache of known folders, not across the whole disk. A library in /usr/local/lib, or in an application’s own folder, may not be in it:

Terminal window
ldconfig -p | grep libfoo
sudo find / -name 'libfoo.so*' 2>/dev/null

Add the folder, and rebuild the cache:

Terminal window
echo '/opt/foo/lib' | sudo tee /etc/ld.so.conf.d/foo.conf
sudo ldconfig

After installing from source to /usr/local/lib, a plain sudo ldconfig is often all that’s missing.

For one program only, without changing the system, use an environment variable:

Terminal window
LD_LIBRARY_PATH=/opt/foo/lib ./app

It works, but it’s fragile: sudo and cron drop it. For services, set Environment=LD_LIBRARY_PATH=... in the unit, or a proper .conf file as above.

Also check the architecture. A 32-bit program needs 32-bit libraries, even if the 64-bit ones are there. file ./app tells you which it is, and on Debian, that needs libc6:i386 and the like.

5. GLIBC_2.xx not found

./app: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by ./app)

The program was compiled on a newer system, and uses features your glibc doesn’t have. See what you have, and what it wants:

Terminal window
ldd --version | head -n 1
objdump -T ./app | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -n 3

Here are the typical glibc versions, so you can see which system would do:

System glibc
Debian 11 2.31
Ubuntu 22.04 2.35
Debian 12 2.36
RHEL 9 2.34
Ubuntu 24.04 2.39
Debian 13 2.41

So what do you do?

  • Get a build made for your system. Vendors often offer one, or a static or musl build.
  • Build it yourself on your system, or on the oldest one you support. A binary built on an old glibc runs on newer ones, and not the other way round.
  • Run it in a container with a newer base image.
  • Upgrade the machine to a newer release.

In CI, this comes up when building on ubuntu-latest and deploying to an older server. Build in a container of your oldest target, or link statically: with Go, CGO_ENABLED=0.

Never replace your system’s glibc by hand, or install a newer one over it. Nearly every program depends on it, including ls, bash and sudo, so a mismatch can leave you with a machine that can’t run any command, and doesn’t boot.

6. In Docker

This shows up when you copy a binary between images. For example, built on debian:13 and run on debian:11, or the same thing with libraries missing on a -slim image:

FROM debian:13-slim AS build
# ...
FROM debian:13-slim # the same release as the build
RUN apt-get update && apt-get install -y --no-install-recommends libpq5
COPY --from=build /app /app

To see what’s missing in the final image, run docker run --rm -it myimage ldd /app. For Go, the Dockerfile Generator builds with cgo turned off, so the binary needs no libraries at all. Alpine is a different problem, as it has no glibc at all: see not found for a binary that’s there.

Warning

Don’t download a .so from a website to get past this. A library runs inside your program, with all its rights. Use your distribution’s packages, or the vendor’s.

Shell, we have a problem!

Similar, but different: command not found means the program itself isn’t on your PATH. no such file or directory for a file that’s right there often means its loader is missing: see the Alpine article. exec format error means another CPU architecture: see that article. And Python’s ImportError: libfoo.so is this same problem, in a Python package.

Found this useful? Share it.

Found a mistake? Let us know at contact@ohsudo.com.

Tools

Try it yourself

Articles

Related articles