Werkzeug: 0.15.0 causes OSError: [Errno 8] Exec format error: in Docker for Windows

Created on 21 Mar 2019  ·  19Comments  ·  Source: pallets/werkzeug

The new 0.15.0 does not run in Docker for Windows. Have not tried Docker on other platforms.

Minimal example with Flask.

app.py

from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello, world!'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Dockerfile

FROM python:3-onbuild
COPY . /usr/src/app
CMD ["python", "app.py"]

requirements.txt

# Werkzeug==0.14.1
Flask

Run docker build -t flask_test . and then docker run flask_test.
Error in container:

λ docker run flask_test
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
Traceback (most recent call last):
  File "app.py", line 11, in <module>
    app.run(debug=True, host='0.0.0.0')
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 943, in run
    run_simple(host, port, self, **options)
  File "/usr/local/lib/python3.6/site-packages/werkzeug/serving.py", line 988, in run_simple
    run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
  File "/usr/local/lib/python3.6/site-packages/werkzeug/_reloader.py", line 332, in run_with_reloader
    sys.exit(reloader.restart_with_reloader())
  File "/usr/local/lib/python3.6/site-packages/werkzeug/_reloader.py", line 176, in restart_with_reloader
    exit_code = subprocess.call(args, env=new_environ, close_fds=False)
  File "/usr/local/lib/python3.6/subprocess.py", line 267, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/local/lib/python3.6/subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "/usr/local/lib/python3.6/subprocess.py", line 1344, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: '/usr/src/app/app.py

Uncomment the first line in requirements.txt and it runs properly after rebuild.

Most helpful comment

Did the same tutorial and found the same issue. This fixed it for me.

I added the following shebang to the top of my app.py script

#!/usr/local/bin/python3

Which then caused permission issues. I then added the following to my Dockerfile before the CMD

RUN chmod 644 app.py

All 19 comments

Hi same issue here. Tested on

  • Centos 7.4 with python 3.6
  • Mac OSX 10.14.3 with python 3.7

This is caused by the changes in _get_args_for_reloading() in _reloading.py.

Given the code above in a file called app.py, with cwd() being /home/user/Projects/test/

_get_args_for_reloading() yields the following:

With 0.14.1:

['/home/user/.virtualenvs/test-ChRUEUMK/bin/python', 'app.py']

With 0.15.0

['/home/user/Projects/test/app.py']

Prepending /home/user/.virtualenvs/test-ChRUEUMK/bin/python to the path does fix the issue.

@shinuza check if app.py is executable, if yes - set chmod 644 app.py. Or second way, add shebang on the top of app.py like #!/usr/bin/env python

@shinuza there https://github.com/pallets/werkzeug/blob/0.15.x/src/werkzeug/_reloader.py#L90 lines 90-94 the "'/home/user/.virtualenvs/test-ChRUEUMK/bin/python'" was removed if app.py executable.
and OSError: [Errno 8] Exec format error: '/usr/src/app/app.py happened because app.py doesn't have shebang line (https://stackoverflow.com/questions/27606653/oserror-errno-8-exec-format-error)

@kamyanskiy I just figured this out reading the code but the error should be as cryptic as it is right now.

Also, if I explicitly run python app.py, then the subprocess should not make any assumption and change the way I run the application. i.e: working with a virtual machine with shared folder makes every files executable by default.

@shinuza I don't think its a critical bug, in other words its a bit stricter now than before. So I shouldn't have executable app.py without shebang, it doesn't make sense. And second I shouldn't run executable with shebang like "python app.py". But I agree, probably that was unexpected for you as for me :) To workaround just add shebang to your app.py, I hope this will help.

If you mark a script as executable, you should add a corresponding interpreter comment to the top. You can use a tool like pre-commit's check-executables-have-shebangs hook to enforce that.

If you don't intend for a script to be directly executable, and want to require python script.py instead, then you should not mark it executable.

As I said, I agree with the main logic here. I disagree with the way the error is dealt with as well as the fact that the error message is unintelligible unless you know the know the technical details or read the code. It should at least be documented in the changelog.

We have no control over the error message, that comes from Linux. The fact that we changed how executable files are handled is listed in the changelog:

The reloader will not prepend the Python executable to the command line if the Python file is marked executable. This allows the reloader to work on NixOS. #1242

Making the file not executable works. The shebang line does not, for me. I get file not found errors, instead. That was the first thing I tried.

With #!/usr/bin/env python3:

λ docker run flask_test
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
: No such file or directory

I also think making a change that works only on one Linux distribution but breaks the rest doesn't seem ideal. Making the files not executable seems like the proper solution, but this still feels broken to me.

@penner42 try #!/usr/bin/env python

root@4541ebd677e0:/usr/src/app# ls -la /usr/local/bin/python3
lrwxrwxrwx 1 root staff 9 Mar  4 23:40 /usr/local/bin/python3 -> python3.6
root@4541ebd677e0:/usr/src/app# ls -la /usr/local/bin/python 
lrwxrwxrwx 1 root staff 7 Mar  4 23:40 /usr/local/bin/python -> python3

probably you don't have symlink on python3

Same result. The python3 symlink is there, and just running /usr/bin/env python3 or /usr/bin/env python from a shell works.

FWIW, Docker does gives this warning when building.
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

Use the flask run command.

FROM python:3.7-alpine
WORKDIR /app
ENV FLASK_ENV development
ENV FLASK_APP example
EXPOSE 5000
RUN ["pip", "install", "flask"]
CMD ["flask", "run", "-h", "0.0.0.0"]
docker run --rm -p 5000:5000 -v $(pwd):/app flask/example:latest

Did the tutorial at https://docs.docker.com/compose/gettingstarted/ used to work on Windows 7?
Is this recent change the cause why I see a similar error trying to run the example:

$ docker-compose up
Creating composetest_web_1   ... done
Creating composetest_redis_1 ... done
Attaching to composetest_web_1, composetest_redis_1
redis_1  | 1:C 27 Mar 2019 17:29:12.746 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 27 Mar 2019 17:29:12.746 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 27 Mar 2019 17:29:12.747 # Warning: no config file specified, using the default config. In order to specify a config file use redis-ser
ver /path/to/redis.conf
redis_1  | 1:M 27 Mar 2019 17:29:12.757 * Running mode=standalone, port=6379.
redis_1  | 1:M 27 Mar 2019 17:29:12.757 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to th
e lower value of 128.
redis_1  | 1:M 27 Mar 2019 17:29:12.758 # Server initialized
redis_1  | 1:M 27 Mar 2019 17:29:12.758 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issu
e add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
web_1    |  * Serving Flask app "app" (lazy loading)
web_1    |  * Environment: production
web_1    |    WARNING: Do not use the development server in a production environment.
web_1    |    Use a production WSGI server instead.
web_1    |  * Debug mode: on
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1    |  * Restarting with stat
web_1    | Traceback (most recent call last):
web_1    |   File "app.py", line 32, in <module>
web_1    |     app.run(host="0.0.0.0", debug=True)
web_1    |   File "/usr/local/lib/python3.4/site-packages/flask/app.py", line 943, in run
web_1    |     run_simple(host, port, self, **options)
web_1    |   File "/usr/local/lib/python3.4/site-packages/werkzeug/serving.py", line 988, in run_simple
web_1    |     run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
web_1    |   File "/usr/local/lib/python3.4/site-packages/werkzeug/_reloader.py", line 332, in run_with_reloader
web_1    |     sys.exit(reloader.restart_with_reloader())
web_1    |   File "/usr/local/lib/python3.4/site-packages/werkzeug/_reloader.py", line 176, in restart_with_reloader
web_1    |     exit_code = subprocess.call(args, env=new_environ, close_fds=False)
web_1    |   File "/usr/local/lib/python3.4/subprocess.py", line 534, in call
web_1    |     with Popen(*popenargs, **kwargs) as p:
web_1    |   File "/usr/local/lib/python3.4/subprocess.py", line 856, in __init__
web_1    |     restore_signals, start_new_session)
web_1    |   File "/usr/local/lib/python3.4/subprocess.py", line 1464, in _execute_child
web_1    |     raise child_exception_type(errno_num, err_msg)
web_1    | OSError: [Errno 8] Exec format error
composetest_web_1 exited with code 1

Did the same tutorial and found the same issue. This fixed it for me.

I added the following shebang to the top of my app.py script

#!/usr/local/bin/python3

Which then caused permission issues. I then added the following to my Dockerfile before the CMD

RUN chmod 644 app.py

Please anyone can update the tutorial (https://docs.docker.com/compose/gettingstarted/)
to add

RUN chmod 644 app.py

Changes to Docker Compose tutorial proposed in https://github.com/docker/docker.github.io/pull/8609.

Fixed in Werkzeug 0.15.5.

Was this page helpful?
0 / 5 - 0 ratings