Skip to content

Windows shell subprocess fails to execute when PATH is sufficiently long and first argument is not a full path #137254

@boimart1

Description

@boimart1

Bug report

Bug description:

Note: This is likely a limitation with cmd.exe itself. Would it be possible and/or desirable to work around this limitation in the subprocess implementation? If not, then go ahead and close this bug as "will not fix". At least it will be documented for future users :)

Description

When calling subprocess.run() or Popen() under the following conditions:

  • env is an environment whose PATH is over ~8200 characters,
  • shell=True,
  • The first argument of args is not a full path to the executable, just a program that is expected to be found in env["PATH"],

then subprocess will call _winapi.CreateProcess() with:

  • executable = 'C:\WINDOWS\system32\cmd.exe'
  • args = 'C:\WINDOWS\system32\cmd.exe /c "subscript"'

And the underlying cmd.exe invocation will be unable to find "subscript".

Repro

Setup a small project with the following structure:

- demo/
  - scripts/
    - subscript.cmd
  - script.py
:: demo/scripts/subscript.cmd
@echo Hello, world!
# demo/script.py
import os, sys, pathlib, subprocess

scripts_dir = pathlib.Path("scripts").resolve()
fake_path = "C:\\NotAPath"

env = os.environ.copy()
path_elems = [str(scripts_dir), env["PATH"]]
for _ in range(1000):
    path_elems.append(fake_path)

env["PATH"] = os.pathsep.join(path_elems)
print("PATH length:", len(env["PATH"]))

subprocess.run("subscript", env=env, shell=True)

And run py script.py.

Expected result

"subscript.cmd" is executed and "Hello, world!" is printed.

Actual result

The following message is printed.

'subscript' is not recognized as an internal or external command,
operable program or batch file.

Workarounds

Performing any of the following will produce the correct output:

  • The user can resolve the path to subscript.cmd in advance with shutil.which('subscript', path=env['PATH']), and pass the result to subprocess.run(). In fact, this step would be necessary if shell was False, since subscript.cmd is not on the current process's PATH.
  • After some experimentation, I've found that the PATH length limit is exactly 8191 characters. Having a PATH of this length or lower will work; any longer and the above issue is observed.

In my real situation, the call to subprocess is in a library I am using and I cannot modify its arguments. In addition, in the context where this call is made, the PATH is very long by necessity.

CPython versions tested on:

3.13, 3.12, 3.11, 3.10

Operating systems tested on:

Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions