Bug report
If something goes wrong in subprocess after spawning the child process but before exec, subprocess assumes the only possible error can be from changing directory to the cwd=... argument and adds that path to the exception. I suppose this was correct at some point in the distant past, but there are many things that subprocess can do pre-exec.
The relevant code is this, from _execute_child in Lib/subprocess.py:
if issubclass(child_exception_type, OSError) and hex_errno:
errno_num = int(hex_errno, 16)
child_exec_never_called = (err_msg == "noexec")
if child_exec_never_called:
err_msg = ""
# The error must be from chdir(cwd).
err_filename = cwd
else:
err_filename = orig_executable
if errno_num != 0:
err_msg = os.strerror(errno_num)
raise child_exception_type(errno_num, err_msg, err_filename)
That comment is wrong - there's now many things that can fail in the noexec phase in Modules/_posixsubprocess.c, all of which (besides preexec_fn) report errno to the parent as OSError. Here's a couple of sample misleading errors:
>>> subprocess.check_call(["pwd"], pass_fds=[30,], cwd="/tmp")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 368, in check_call
retcode = call(*popenargs, **kwargs)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 349, in call
with Popen(*popenargs, **kwargs) as p:
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 951, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 1821, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 9] Bad file descriptor: '/tmp'
>>> subprocess.check_call(["pwd"], user="root", cwd="/tmp")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 368, in check_call
retcode = call(*popenargs, **kwargs)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 349, in call
with Popen(*popenargs, **kwargs) as p:
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 951, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/subprocess.py", line 1821, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
PermissionError: [Errno 1] Operation not permitted: '/tmp'
(The same issue also happens with asyncio.create_subprocess_exec which uses subprocess.Popen under the hood.)
Your environment
Tested on macOS Ventura 13.3's /usr/bin/python3 (3.9.6) as well as docker run --rm -it python:3.12.0a7-bullseye.
Linked PRs
Bug report
If something goes wrong in
subprocessafter spawning the child process but before exec, subprocess assumes the only possible error can be from changing directory to thecwd=...argument and adds that path to the exception. I suppose this was correct at some point in the distant past, but there are many things thatsubprocesscan do pre-exec.The relevant code is this, from
_execute_childinLib/subprocess.py:That comment is wrong - there's now many things that can fail in the
noexecphase inModules/_posixsubprocess.c, all of which (besidespreexec_fn) report errno to the parent asOSError. Here's a couple of sample misleading errors:(The same issue also happens with
asyncio.create_subprocess_execwhich usessubprocess.Popenunder the hood.)Your environment
Tested on macOS Ventura 13.3's /usr/bin/python3 (3.9.6) as well as
docker run --rm -it python:3.12.0a7-bullseye.Linked PRs