28

I have a Python script, which is running as a Windows Service. The script forks another process with:

with subprocess.Popen( args=[self.exec_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as proc:

which causes the following error:

OSError: [WinError 6] The handle is invalid
   File "C:\Program Files (x86)\Python35-32\lib\subprocess.py", line 911, in __init__
   File "C:\Program Files (x86)\Python35-32\lib\subprocess.py", line 1117, in _get_handles
Alastair McCormack
  • 26,573
  • 8
  • 77
  • 100

2 Answers2

44

Line 1117 in subprocess.py is:

p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE)

which made me suspect that service processes do not have a STDIN associated with them (TBC)

This troublesome code can be avoided by supplying a file or null device as the stdin argument to popen.

In Python 3.x, you can simply pass stdin=subprocess.DEVNULL. E.g.

subprocess.Popen( args=[self.exec_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL)

In Python 2.x, you need to get a filehandler to null, then pass that to popen:

devnull = open(os.devnull, 'wb')
subprocess.Popen( args=[self.exec_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=devnull)
Alastair McCormack
  • 26,573
  • 8
  • 77
  • 100
  • 1
    Service executables (e.g. pythonservice.exe) are run detached (i.e. not attached to an instance of conhost.exe), in which case `GetStdHandle` should return `NULL`, not `INVALID_HANDLE_VALUE`. – Eryk Sun Oct 18 '16 at 20:25
  • 2
    A similar error is common when running via pythonw.exe. Prior to Windows 8, a pythonw.exe process has console handle values in its standard handles, but they're invalid since there's no attached console. subprocess raises an error when it tries to call `DuplicateHandle` on the invalid handle. – Eryk Sun Oct 18 '16 at 20:28
  • 5
    Ok, I think I have the edgiest of edge cases here, so I'm not sure anyone else will find it - My script has been compiled into a standalone .exe using PyInstaller. The script isn't the actual service - a C#/.net app is the service which forks the standalone .exe. The service has a standalone mode, which, when executed as a desktop user, works as expected. – Alastair McCormack Oct 18 '16 at 20:49
  • Thanks for the help, I had a few dependency python packages which broke after configuring application to run as a Windows Service - same issue and workaround used to fix. – user297500 Feb 07 '18 at 15:50
  • 2
    similar error comes in Python 3.6 for `subprocess.run( cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)` when running inside nested (subprocess.Popen, Windows Application, python via DLL). adding `stdin = subprocess.DEVNULL` fixed it. – hardmooth Feb 27 '18 at 07:16
  • Ran into the same issue after I packaged a script with Pyinstaller. Using subprocess.DEVNULL did the trick. Big thanks ! – Mathias Dolidon Jan 02 '19 at 09:58
  • Stupid question, but you set stdin as DEVNULL in the original subprocesses module, or in the erroneous script that calls subprocesses ? If it is the first - can you tell me where to find it exactly? If it is the second - I tried adding it as keyword argument in the subprocess.Popen, as well as in the subprocess.call line (where the error actually happens), using kwargs['stdin'] = devnull, but it doesn't solve the problem. :( – ISquared Aug 07 '20 at 12:06
  • @Isquare1 you only need to fix your code (or 3rd party code), not Python's codebase. – Alastair McCormack Aug 07 '20 at 13:31
  • Dude, you saved me! Run on this problem like this: `Popen(['ping', '192.168.0.1'], stdout=PIPE, stderr=PIPE)`. Seems you had to support stdin if you supported stdout and stderr. – Smit Johnth Aug 02 '21 at 17:12
  • Hey @SmitJohnth. Top tip, use native Python libraries, like https://pypi.org/project/icmplib/, where you can. It's more powerful and you'll find it much easier to handle errors. – Alastair McCormack Aug 02 '21 at 17:16
  • @AlastairMcCormack Can it report while working? The call simply blocked for me. – Smit Johnth Aug 02 '21 at 17:23
  • 1
    @SmitJohnth looks like it has a count option. Set it to `1` and loop. – Alastair McCormack Aug 02 '21 at 17:28
  • @AlastairMcCormack well... I almost already written this using subprocess. And this lib requires root. I'll still need subprocess at some time. – Smit Johnth Aug 02 '21 at 17:32
3

Add stdin=subprocess.PIPE like:

with subprocess.Popen( args=[self.exec_path], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) as proc:
zelusp
  • 3,500
  • 3
  • 31
  • 65