366

I have a docker image which installs grunt, but when I try to run it, I get an error:

Error response from daemon: Cannot start container foo_1: \
    exec: "grunt serve": executable file not found in $PATH

If I run bash in interactive mode, grunt is available.

What am I doing wrong?

Here is my Dockerfile:

# https://registry.hub.docker.com/u/dockerfile/nodejs/ (builds on ubuntu:14.04)
FROM dockerfile/nodejs

MAINTAINER My Name, me@email.com

ENV HOME /home/web
WORKDIR /home/web/site

RUN useradd web -d /home/web -s /bin/bash -m

RUN npm install -g grunt-cli
RUN npm install -g bower

RUN chown -R web:web /home/web
USER web

RUN git clone https://github.com/repo/site /home/web/site

RUN npm install
RUN bower install --config.interactive=false --allow-root

ENV NODE_ENV development

# Port 9000 for server
# Port 35729 for livereload
EXPOSE 9000 35729
CMD ["grunt"]
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • may you try to build the docker using `CMD grunt`? Or may you try to execute the grunt command by passing the full path? – mgaido Nov 26 '14 at 21:45
  • @mark91 please could you elaborate on what you're asking re build using `CMD grunt?` Do you mean drop the `["` and `"]`? – Steve Lorimer Nov 26 '14 at 21:49
  • 1
    Just tried it - and it worked - thanks! So for anyone else coming in, change `CMD ["grunt"]` to `CMD grunt` – Steve Lorimer Nov 26 '14 at 21:50
  • 14
    This is because if you do `CMD ["grunt"]` you use another shell to execute the command, so in that shell $PATH is likely not to be set. – mgaido Nov 27 '14 at 08:47
  • See also https://stackoverflow.com/q/48001082/798677 – That Brazilian Guy Apr 08 '19 at 15:34
  • If you're running a custom script, try ENTRYPOINT instead of CMD – gary69 Jul 18 '19 at 19:02
  • *"This is because if you do `CMD ["grunt"]` you use another shell to execute the command"*. No, actually `CMD ["grunt"]` runs without ANY shell. See https://stackoverflow.com/questions/27158840/docker-executable-file-not-found-in-path/27615958#27615958 – wisbucky Sep 04 '19 at 23:13

14 Answers14

558

This was the first result on google when I pasted my error message, and it's because my arguments were out of order.

The container name has to be after all of the arguments.

Bad:

docker run <container_name> -v $(pwd):/src -it

Good:

docker run -v $(pwd):/src -it <container_name>
Kabir Sarin
  • 18,092
  • 10
  • 50
  • 41
  • 274
    If you always read documentation thoroughly before you started coding, you'd never get anything done. When you bought your new car, did you read the 200 page manual before you drove it home? No. And when there was a problem with your car, did you google it first, or did you go get the manual? This is totally reasonable, I can only imagine all of the people who found it useful but haven't clicked the upvote button! What's kind of unreasonable is that this totally-unrelated answer is the first google result for this error message, or that the docker cli is unintuitive and unforgiving. Cheers. – Kabir Sarin Nov 30 '16 at 10:17
  • 13
    In many scripts the order of the flags is not important, so I can see why this can happen to anyone. The answer is quite helpful. Needless to say that the error message from docker is not useful at all. – marios Jan 12 '17 at 20:09
  • 9
    Wow, I would've struggled for a while if not for this answer. Why doesn't UNIX have a standard, flexible and powerful CLI argument parser already?... – lleaff Feb 03 '17 at 13:58
  • 1
    This was the issue for me. Putting container name on the end seemed to work – Rob Segal Apr 06 '17 at 21:50
  • 4
    I was mislead by the accepted answer, wanted to write my own, but seems it's here already. So I can confirm that this solves the problem... – Arturas M Sep 30 '17 at 20:27
  • 2
    This is the core of the issue – tom10271 Dec 11 '17 at 03:45
  • I tried to get this to work but it still says that the database is unintialized and hasn't set the password. Do I include a password param after it? my command is: `docker run -v $(pwd):/src -it mysql` EDIT: my docker-compose.yml has `MYSQL_USER=root MYSQL_ROOT_PASSWORD=password MYSQL_DB=bpal` under **environment:** – Norseback May 10 '18 at 02:00
  • This solved my issue. Also, the sample docker command in the Shared Drives menu is confusing. The "alpine ls /data" part at the end is unnecessary, it's not clear what "alpine" means there.. – Alkanshel Nov 28 '18 at 21:06
  • Same for docker-compose.yml if you write "command: my_app" too early in file then it might not find it. So consider writing "command : my_app" last – Sergey Anisimov Sep 21 '21 at 11:03
  • I'm never getting that hour of my life back for thinking that `docker run -d -v ` was more readable than `docker run -v -d `, nor for thinking `-d ` was an option. In reality, it's `docker run [OPTIONS] IMAGE...`, and `-d` is the `detached` option. Never getting that back. So much for tidying up my scripts. – cod3monk3y Jan 25 '22 at 20:45
  • THIS issue took up a few hours of my time! Glad I found this post. Thank you so much.✌✌ – Isaac I9 Dec 02 '22 at 17:13
277

When you use the exec format for a command (e.g., CMD ["grunt"], a JSON array with double quotes), it will be executed without a shell. This means that most environment variables will not be present.

If you specify your command as a regular string (e.g. CMD grunt) then the string after CMD will be executed with /bin/sh -c.

More info on this is available in the CMD section of the Dockerfile reference.

Amin Shojaei
  • 5,451
  • 2
  • 38
  • 46
Kevan Ahlquist
  • 5,375
  • 1
  • 17
  • 25
  • 3
    This is a link to the CMD portion of the reference https://docs.docker.com/engine/reference/builder/#cmd – Calvin Mar 19 '19 at 20:31
  • 1
    Excuse this dumb question, but how can you execute a linux command without a shell? What would be the equivalent to do this on a linux machine (not using docker)? – wisbucky Sep 03 '19 at 17:56
  • 1
    To answer my own question, it is similar to doing `sudo set` or `(exec set)`. Those will fail because they execute the commands without a shell (and `set` is a shell builtin). However, `sudo ls` and `(exec ls)` will work because `ls` is an actual binary file `/bin/ls`. – wisbucky Sep 04 '19 at 23:12
  • WOW, so simple, i been trying so hard to fix this, something so silly THANKS! – pelos Feb 17 '22 at 14:46
33

I found the same problem. I did the following:

docker run -ti devops -v /tmp:/tmp /bin/bash

When I change it to

docker run -ti -v /tmp:/tmp devops /bin/bash

it works fine.

rlandster
  • 7,294
  • 14
  • 58
  • 96
keniee van
  • 483
  • 4
  • 5
  • 2
    It worked for me man, But I don't understand the usage of `-v` here. `-v` is to bind mount a volume (as described in `docker run --help | grep "\-v"`), for me, I already have `/tmp` mounted in the `File Sharing` (Docker settings), so why should I use it again? – Ahmad Mar 03 '18 at 12:56
23

For some reason, I get that error unless I add the "bash" clarifier. Even adding "#!/bin/bash" to the top of my entrypoint file didn't help.

ENTRYPOINT [ "bash", "entrypoint.sh" ]
beyondtheteal
  • 729
  • 6
  • 15
  • @SteveLorimer, yes. I did a `COPY` and then `RUN chmod +x /compile_nibbler.sh` before the entrypoint call. – beyondtheteal Nov 06 '18 at 16:34
  • I was using a python alpine image and so the command that worked for was `ENTRYPOINT [ "sh", "entrypoint.sh" ]` – lordvcs Dec 03 '21 at 15:13
18

There are several possible reasons for an error like this.

In my case, it was due to the executable file (docker-entrypoint.sh from the Ghost blog Dockerfile) lacking the executable file mode after I'd downloaded it.

Solution: chmod +x docker-entrypoint.sh

Ben Creasy
  • 3,825
  • 4
  • 40
  • 50
12

I had the same problem, After lots of googling, I couldn't find out how to fix it.

Suddenly I noticed my stupid mistake :)

As mentioned in the docs, the last part of docker run is the command you want to run and its arguments after loading up the container.

NOT THE CONTAINER NAME !!!

That was my embarrassing mistake.

Below I provided you with the picture of my command line to see what I have done wrong.

And this is the fix as mentioned in the docs.

enter image description here

Parsa
  • 7,995
  • 2
  • 27
  • 37
8

A Docker container might be built without a shell (e.g. https://github.com/fluent/fluent-bit-docker-image/issues/19).

In this case, you can copy-in a statically compiled shell and execute it, e.g.

docker create --name temp-busybox busybox:1.31.0
docker cp temp-busybox:/bin/busybox busybox
docker cp busybox mycontainerid:/busybox
docker exec -it mycontainerid /bin/busybox sh
schnatterer
  • 7,525
  • 7
  • 61
  • 80
Gajus
  • 69,002
  • 70
  • 275
  • 438
3

In the error message shown:

Error response from daemon: Cannot start container foo_1: \
    exec: "grunt serve": executable file not found in $PATH

It is complaining that it cannot find the executable grunt serve, not that it could not find the executable grunt with the argument serve. The most likely explanation for that specific error is running the command with the json syntax:

[ "grunt serve" ]

in something like your compose file. That's invalid since the json syntax requires you to split up each parameter that would normally be split by the shell on each space for you. E.g.:

[ "grunt", "serve" ]

The other possible way you can get both of those into a single parameter is if you were to quote them into a single arg in your docker run command, e.g.

docker run your_image_name "grunt serve"

and in that case, you need to remove the quotes so it gets passed as separate args to the run command:

docker run your_image_name grunt serve

For others seeing this, the executable file not found means that Linux does not see the binary you are trying to run inside your container with the default $PATH value. That could mean lots of possible causes, here are a few:

  • Did you remember to include the binary inside your image? If you run a multi-stage image, make sure that binary install is run in the final stage. Run your image with an interactive shell and verify it exists:

    docker run -it --rm your_image_name /bin/sh
    
  • Your path when shelling into the container may be modified for the interactive shell, particularly if you use bash, so you may need to specify the full path to the binary inside the container, or you may need to update the path in your Dockerfile with:

    ENV PATH=$PATH:/custom/dir/bin
    
  • The binary may not have execute bits set on it, so you may need to make it executable. Do that with chmod:

    RUN chmod 755 /custom/dir/bin/executable
    
  • The binary may include dynamically linked libraries that do not exist inside the image. You can use ldd to see the list of dynamically linked libraries. A common reason for this is compiling with glibc (most Linux environments) and running with musl (provided by Alpine):

    ldd /path/to/executable
    
  • If you run the image with a volume, that volume can overlay the directory where the executable exists in your image. Volumes do not merge with the image, they get mounted in the filesystem tree same as any other Linux filesystem mount. That means files from the parent filesystem at the mount point are no longer visible. (Note that named volumes are initialized by docker from the image content, but this only happens when the named volume is empty.) So the fix is to not mount volumes on top of paths where you have executables you want to run from the image.

  • If you run a binary for a different platform, and haven't configured binfmt_misc with the --fix-binary option, qemu will be looking for the interpreter inside the container filesystem namespace instead of the host filesystem. See this Ubuntu bug report for more details on this issue.

  • If the error is from a shell script, the issue is often with the first line of that script (e.g. the #!/bin/bash). Either the command doesn't exist inside the image for a reason above, or the file is not saved as ascii or utf8 with Linux linefeeds. You can attempt dos2unix to fix the linefeeds, or check your git and editor settings.

BMitch
  • 231,797
  • 42
  • 475
  • 450
3

in my case i order params wrong move all switchs before image name

  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 17 '22 at 19:36
  • Indeed that was the reason for me. Thanks! – Bo Yi Feb 13 '23 at 18:28
2

I got this error message, when I was building alpine base image :

ERROR: for web  Cannot start service web: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "bash": executable file not found in $PATH: unknown

In my docker-compose file, I had the command directive in which executing command using bash and bash does not come with alpine base image.

command: bash -c "python manage.py runserver 0.0.0.0:8000"

Then I realized and executed command using sh (shell). It worked for me.

1

problem is glibc, which is not part of apline base iamge.

After adding it worked for me :)

Here are the steps to get the glibc

apk --no-cache add ca-certificates wget
wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
apk add glibc-2.28-r0.apk
1

I ran into this issue using docker-compose. None of the solutions here or on this related question resolved my issue. Ultimately what worked for me was clearing all cached docker artifacts with docker prune -a and restarting docker.

Vito
  • 1,580
  • 1
  • 17
  • 32
0

Refering to the title.

My mistake was to put variables via --env-file during docker run. Among others the file consisted of a PATH extension: PATH=$PATH:something, which caused PATH var look literally like PATH=$PATH:something (var resolution hadn't been performed) instead of PATH:/usr/bin...:something.

I couldn't make the resolution work through --env-file, so the only way I see this working is by using ENV in Dockerfile.

Jon
  • 159
  • 2
  • 5
-8

to make it work add soft reference to /usr/bin:

ln -s $(which node) /usr/bin/node

ln -s $(which npm) /usr/bin/npm

vacavaca
  • 5
  • 1