You’re calm, creating a new Dockerfile for your project like any other day.
You leave the Docker image building while you get up to refill your coffee cup, but suddenly:
=> [build 8/10] COPY ./scripts ./scripts
=> [build 9/10] RUN npx nx build app --prod
=> ERROR [build 10/10] RUN ./scripts/set-build-version.sh
------
> [build 10/10] RUN ./scripts/set-build-version.sh:
#17 0.345 /bin/sh: ./scripts/set-build-version.sh: not found
------
executor failed running [/bin/sh -c ./scripts/set-build-version.sh]: exit code: 127
The classic 127 error, telling you that ./scripts/set-build-version.sh was not found. But you know the file is there. You literally copied it two steps earlier.
You check the code, check the folder, check the code again… and start questioning your sanity.
The investigation
As much as I’d like to blame dark magic and call it a day, reality is less forgiving. I needed this to work. So the first logical thought is: okay, maybe the script isn’t being copied for some reason.
Time to debug. Let’s list the files inside the image:
#16 [build 9/11] RUN echo $(ls -al scripts)
#16 0.338 total 28
drwxr-xr-x 2 root root 4096 Nov 21 11:37 .
drwxr-xr-x 1 root root 4096 Nov 21 11:38 ..
-rwxr-xr-x 1 root root 708 Nov 21 11:37 build-and-upload-containers.sh
-rwxr-xr-x 1 root root 2478 Oct 15 11:46 deploy.sh
-rwxr-xr-x 1 root root 455 Sep 30 10:33 initialization.sh
-rwxr-xr-x 1 root root 201 Nov 21 11:30 set-build-version.sh
#16 DONE 0.4s
Hmm… there it is. Correct permissions and everything.
If the file exists and is executable, why does /bin/sh claim it can’t be found?
Appearances are deceptive
This is where things get interesting. When Docker says “not found”, it doesn’t always mean the script itself is missing. Sometimes it means what the script needs in order to run is missing.
1. The missing shebang
If your script starts with #!/bin/bash but you’re using an Alpine Linux base image, you’ll get a “not found” error.
Why? Because Alpine doesn’t include bash by default. It uses its leaner sibling, sh. The system tries to locate /bin/bash to execute the script, fails to find it, and everything blows up.
2. Line endings
The classic, well-known arch-villain. If the script was created on Windows, it may use CRLF line endings. That can result in the shebang effectively becoming something like /bin/sh\r, even though those extra characters are invisible.
So just to be safe:
RUN sed -i 's/\r$//' ./scripts/set-build-version.sh && \
chmod +x ./scripts/set-build-version.sh
Problem solved:
=> [build 9/10] RUN sed -i 's/\r$//' ./scripts/set-build-version.sh && chmod +x ./scripts/set-build-version.sh
=> [build 10/10] RUN ./scripts/set-build-version.sh
=> CACHED [stage-1 2/4] WORKDIR /app
And now, finally, back to my coffee.