Search code examples
pythonsubprocess

CalledProcessError.stderr of subprocess.check_call is None despite the process outputting an error message


I'm trying to capture the error message of a program called by subprocess.check_call but the stderr in the error object is always None.

Here is a short script that shows this:

import subprocess
import sys

if '--fail' in sys.argv:  # the script calls itself with this option, for the test
    print('this is the error message', file=sys.stderr)
    sys.exit(1)

try:
    subprocess.check_call([sys.executable, sys.argv[0], '--fail'],
                          stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
    print('Not failed?')  # this neither happens nor is expected
except subprocess.CalledProcessError as err:
    if err.stderr:
        print(err.stderr.decode())  # this is what I expect
    else:
        print('<No error message>')  # this is what happens

I have Python 3.10.12.


Solution

  • You didn't communicate with the subprocess at all, so the content is still buffered in the pipe.

    The docs of check_call have this notice:

    Note: Do not use stdout=PIPE or stderr=PIPE with this function.

    Instead of this:

    subprocess.check_call([sys.executable, sys.argv[0], '--fail'],
                          stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
    

    Use the higher level API of run:

    subprocess.run([sys.executable, sys.argv[0], '--fail'],
                   capture_output=True, check=True)