How to get exit code when using Python subprocess communicate method?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When you run a child process in Python, communicate() is used to read its output safely and wait for it to finish. The exit code is not returned directly by communicate(), but it is available immediately afterward through the process object's returncode attribute.
Basic Pattern with Popen
The normal sequence is:
- create the process with
subprocess.Popen - call
communicate()to wait for completion and collect output - read
proc.returncode
After communicate() returns, the process has finished, so proc.returncode contains the exit status. Before the process finishes, returncode is None.
Why communicate() Is Preferred
If you redirect both standard output and standard error to pipes, reading them manually can deadlock if one buffer fills up while you are waiting on the other. communicate() is the safe built-in API that drains the pipes and waits for termination in the intended order.
That is why the usual advice is not just "call wait() and then inspect returncode." If you also need the captured output, communicate() is the right companion method.
A Small Helper Function
In real code, subprocess handling is often repeated many times. Wrapping it in a helper keeps error handling and timeout behavior consistent.
The key idea is still the same: the exit code comes from proc.returncode, not from the tuple returned by communicate().
Using subprocess.run When You Do Not Need Popen
If all you want is to execute one command, wait, capture output, and inspect the exit code, subprocess.run is shorter and usually clearer.
Under the hood, run handles the common pattern for you. Use Popen when you need finer control, such as streaming input, connecting multiple child processes, or interacting with the process before it exits.
Interpreting Nonzero Exit Codes
A nonzero exit code does not always mean the same thing. Each external program defines its own meanings. For one tool, 1 might mean validation errors were found. For another, 1 might mean a fatal runtime failure.
That means your application should not just check "zero or nonzero" if the command contract is more specific.
Treat the exit code as part of the API offered by the external command.
Common Pitfalls
- Expecting
communicate()itself to return the exit code. - Checking
proc.returncodebefore the child process has actually exited. - Using
wait()when you also need piped output, then risking deadlocks with manual reads. - Ignoring
stderr, which often contains the only useful error message. - Using
shell=Trueunnecessarily and making argument handling or security harder.
Summary
- '
communicate()returns captured output, not the exit code.' - Read the exit status from
proc.returncodeaftercommunicate()completes. - Use
communicate()when output is piped because it avoids common deadlock patterns. - Wrap subprocess logic in a helper if your code runs many commands.
- Prefer
subprocess.runfor the simple one-command case.
Related reading
- How to get feature names selected by feature elimination in sklearn pipeline?
- How to get first element in a list of tuples?
- How to get GET request values in Django?
- How to get http headers in flask?
- How to get indices of a sorted array in Python
- How to get JSON from webpage into Python script
- How to get last items of a list in Python?
- How to get Linux console window width in Python
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.