Python subprocess.run different on f45

I’m trying to hunt down a change that appears in pre-rel f45 and rawhide: when you call subprocess.run (or fiddle directly with Popen) with shell=False, and the command to run is not found, the error has changed. Online AI confidently claims that this is an intentional change to make things better for programmers; I can’t, so far, find any other evidence of this. If true, it’s kind of an odd change. An interactive session shows this quite simply. This is the common part:

>>> import subprocess
>>> subprocess.run(["ploppy"], shell=False)
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    subprocess.run(["ploppy"], shell=False)
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^

On all systems I’ve ever looked at the end of the failure message looks like:

  File "/usr/lib64/python3.14/subprocess.py", line 1990, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'ploppy'

On F45/Rawhide it looks like:

  File "/usr/lib64/python3.15/subprocess.py", line 2156, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
NotADirectoryError: [Errno 20] Not a directory: 'ploppy'

(for the avoidance of doubt, it doesn’t change if the first argument is a string or a list of strings)

Why would this be giving an ENOTDIR now? Can someone point me to actual discussion on this change?

If you install python 3.14 on f45 do you see the old error message?
Fyi fedora packages lots of python versions that you can install side by side.

It’s not Python version specific. I previously saw the same behavior with 3.9 (that’s the low end of supported versions for the project I test on these prereleases), and just now tried with 3.14 - all three show the Not a directory error.

Maybe strace can help you here? Try finding out which file is accessed when getting a ENOTDIR. Maybe this is a different folder than you think, and the error message is just misleading?

I have an strace log, but it doesn’t enlighten me a whole lot. For the argument supplied, I see it doing an execve for each element of my PATH combined with the (nonexistent) command name… the first six ENOENT, the final one does the ENOTDIR, and the directory of that one definitely exists.

The error description

       ENOTDIR
              A component of the path prefix of pathname or a script or ELF interpreter is not a directory.

It could perhaps mean that the file exist in that directory but has a bad “#!” line. It could also be an ELF file for a different CPU type.

It doesn’t exist at all - intentionally. It’s a “simple reproducer” from a testcase for my project that suddenly started failing.

On F45 beta updated this morning I get:

>>> import subprocess
>>> subprocess.run(["ploppy"], shell=False)
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    subprocess.run(["ploppy"], shell=False)
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.15/subprocess.py", line 669, in run
    with Popen(*popenargs, **kwargs) as process:
         ~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.15/subprocess.py", line 1213, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                        pass_fds, cwd, env,
                        ^^^^^^^^^^^^^^^^^^^
    ...<5 lines>...
                        gid, gids, uid, umask,
                        ^^^^^^^^^^^^^^^^^^^^^^
                        start_new_session, process_group)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.15/subprocess.py", line 2156, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'ploppy'
>>>

Interesting. Thanks for that data point! I’ll dig a bit and see what could be different about my setup from standard.

I also tried aarch64 F45 with same result.

I have also just tried in a toolbx container and get FileNotFoundError. I didn’t have the Fedora 45 toolbx container image, so it was freshly downloaded before I ran it.

$ toolbox create -r 45
Image required to create Toolbx container.
Download registry.fedoraproject.org/fedora-toolbox:45 ( ... MB)? [y/N]: y
Created container: fedora-toolbox-45
Enter with: toolbox enter fedora-toolbox-45

$ toolbox run -r 45 -- python
Python 3.15.0rc2 (3.15.0~rc2-1.fc45.x86_64, Sep  3 2026, 00:00:00) [GCC 16.2.1 20260819 (Red Hat 16.2.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> [...] # same code
[...]
FileNotFoundError: [Errno 2] No such file or directory: 'ploppy'

All right, problem located and fixed - one of the paths in my $PATH had indeed gotten messed up. After some cleanup activities all is well again. Thanks for the tips, and sorry for pointless noise.