exec ./ClinicApi: no such file or directory from a self-contained .NET app on an Alpine image, when ls shows the file is there, means the app was published for linux-x64 (glibc) and Alpine uses musl. Publish with -r linux-musl-x64 instead.

Changing only the runtime identifier from linux-x64 to linux-musl-x64 made the same Dockerfile produce an image that started.

The error

PS> docker run --rm --name fix10-dn-m1 fix10-dn-lab-musl
exec ./ClinicApi: no such file or directory

The container exited with code 255.

Why it happens

The Dockerfile published self-contained for linux-x64 and copied the output onto mcr.microsoft.com/dotnet/runtime:10.0-alpine:

ARG RID=linux-x64
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG RID
WORKDIR /src
COPY ClinicApi.csproj .
RUN dotnet restore -r $RID
COPY Program.cs .
COPY data ./data
RUN dotnet publish -c Release -r $RID --self-contained true -o /out --no-restore

FROM mcr.microsoft.com/dotnet/runtime:10.0-alpine
WORKDIR /app
COPY --from=build /out .
ENTRYPOINT ["./ClinicApi"]

The message is misleading because ./ClinicApi does exist. The linux-x64 executable contains the path /lib64/ld-linux-x86-64.so.2 once and no ld-musl string (grep -c -a in the build stage printed 1 and 0), and on the Alpine image that path does not exist; /lib holds the musl loader instead:

PS> docker run --rm --name fix10-dn-m3 --entrypoint ls fix10-dn-lab-musl -l /app/ClinicApi /lib64/ld-linux-x86-64.so.2
ls: /lib64/ld-linux-x86-64.so.2: No such file or directory
-rwxr-xr-x    1 root     root         78256 Nov 13 05:33 /app/ClinicApi

PS> docker run --rm --name fix10-dn-m4 --entrypoint ls fix10-dn-lab-musl /lib
apk
firmware
ld-musl-x86_64.so.1
libc.musl-x86_64.so.1
modules-load.d
sysctl.d

The output of the failing run is one line, with no .NET text at all: the program never got as far as starting .NET.

The fix

docker build -q -f Dockerfile.musl --build-arg RID=linux-musl-x64 -t fix10-dn-lab-muslfix .
PS> docker run --rm --name fix10-dn-m2 fix10-dn-lab-muslfix
ClinicApi started on .NET 10.0.10

Both images built without an error; the mismatch between the runtime identifier and the base image showed up only at docker run. The working image reported .NET 10.0.10, the runtime that went into the self-contained publish, not the 10.0.15 that the runtime:10.0-alpine base image lists with dotnet --list-runtimes. In your own Dockerfile, write -r linux-musl-x64 on both the restore and the publish line. The other way out is to keep linux-x64 and change the final FROM to the Ubuntu-based runtime-deps:10.0; a linux-x64 self-contained image on that base (fix10-dn-deps-sc, a sibling console app) printed ClinicApi started on .NET 10.0.10 and Ubuntu 24.04.5 LTS in its /etc/os-release.

When you meet this message, list the file and the loaders first, as above: if the file is there and /lib shows only ld-musl, the runtime identifier is the thing to change, not the COPY line.

How it was reproduced

A console app built on mcr.microsoft.com/dotnet/sdk:10.0 (SDK 10.0.302) with the Dockerfile above, run on mcr.microsoft.com/dotnet/runtime:10.0-alpine (Alpine 3.24.4). The failing image was built with docker build -q -f Dockerfile.musl -t fix10-dn-lab-musl . (the default RID=linux-x64). Docker engine 29.9.3 on Windows 11.

Frequently asked

Which runtime identifier do I use for a .NET app on Alpine?
linux-musl-x64. In the test a linux-x64 self-contained publish failed on runtime:10.0-alpine with exec ./ClinicApi: no such file or directory, and linux-musl-x64 started.
Why does Docker say no such file or directory when the file exists?
In this case the linux-x64 executable contained the path /lib64/ld-linux-x86-64.so.2, the Alpine image had no file at that path and only the musl loader in /lib, and the start failed even though ./ClinicApi was in /app.
Can I run a linux-x64 self-contained .NET app in Docker?
Yes. A linux-x64 self-contained publish of the same kind of app started on mcr.microsoft.com/dotnet/runtime-deps:10.0, and that image reported Ubuntu 24.04.5 LTS in /etc/os-release.

The self-contained publish on runtime-deps is in exec: "dotnet": executable file not found in $PATH; the same "no such file or directory" wording from Windows line endings in a script is in exec /entrypoint.sh: no such file or directory. More decoded errors in the Fixes category.