エラーの内容
Pythonからsubprocess.run()、subprocess.check_call()、またはsubprocess.check_output()を使ってシェルコマンドを呼び出したところ、以下のエラーが発生しました:
subprocess.CalledProcessError: Command '['git', 'push']' returned non-zero exit status 1
これはコマンドがゼロ以外の終了コードで終了した(つまり失敗した)場合に発生します。PythonがCalledProcessErrorを発生させるのは、check=Trueを指定するか、check_call/check_outputを使用するなど、明示的に失敗チェックを要求した場合のみです。
発生原因
すべてのプロセスは終了コードを返します。ゼロは成功を意味し、それ以外は失敗を意味します。デフォルトでは、subprocess.run()はコマンドが失敗してもエラーを発生させず、結果オブジェクトをそのまま返します。check=Trueを渡すと、Pythonはゼロ以外の終了コードをCalledProcessErrorに変換します。
主な原因:
- コマンド自体が失敗した(例:
git pushが拒否された、pip installでパッケージが見つからないなど) - コマンドに誤った引数が渡された
- 依存関係が不足しているか、バイナリがPATHに存在しない
- ファイルまたはディレクトリへのアクセスが拒否された
- スクリプトが明示的に
sys.exit(1)またはexit 1を呼び出している
ステップ1 — 実際のエラー出力を確認する
まず最初に、コマンドが出力した内容を確認してください。subprocessはデフォルトでは何もキャプチャしません。出力はそのままターミナルに流れて消えてしまいます。以下のようにキャプチャしましょう:
import subprocess
result = subprocess.run(
['git', 'push'],
capture_output=True,
text=True
)
print('STDOUT:', result.stdout)
print('STDERR:', result.stderr)
print('Exit code:', result.returncode)
ほとんどの場合、本当のエラーメッセージはstderrに含まれています。確認すれば、多くの場合この時点で解決策が明確になります。
ステップ2 — 例外を適切にキャッチする
check=Trueを使用する場合、クラッシュせずに失敗を処理するためにtry/exceptで呼び出しをラップしてください:
import subprocess
try:
result = subprocess.run(
['git', 'push'],
check=True,
capture_output=True,
text=True
)
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f'Command failed with exit code {e.returncode}')
print(f'STDOUT: {e.stdout}')
print(f'STDERR: {e.stderr}')
例外オブジェクトeには.returncode、.stdout、.stderrが含まれています。これら3つの属性から、何が問題だったかを正確に把握できます。
ステップ3 — 根本原因に基づいて修正する
コマンドが見つからない
stderrにcommand not foundまたはNo such file or directoryと表示されている場合、バイナリがPATHに存在しません。実行前に確認してください:
import shutil
if not shutil.which('mycommand'):
raise EnvironmentError('mycommand is not installed or not in PATH')
または、パス検索を省略してフルパスを使用する方法もあります:
subprocess.run(['/usr/local/bin/mycommand', '--flag'], check=True)
シェル機能(パイプ、リダイレクト、ワイルドカード)
['ls', '-la', '|', 'grep', 'txt']のようにリストで渡してもうまくいきません。パイプ文字はシェル演算子ではなくリテラルの引数として扱われるからです。代わりに文字列とshell=Trueを使用してください:
# 間違い — | は引数ではない
subprocess.run(['ls', '-la', '|', 'grep', 'txt'], check=True)
# 正しい方法
subprocess.run('ls -la | grep txt', shell=True, check=True)
絶対に守るべきルール:ユーザーが入力した文字列をshell=Trueに渡してはいけません。シェルインジェクションの原因になります。ハードコードされた文字列またはサニタイズ済みの入力のみを使用してください。
作業ディレクトリの問題
npm installやmakeなどのコマンドは特定のディレクトリから実行する必要があります。os.chdir()の代わりにcwdを使用してください:
subprocess.run(['npm', 'install'], check=True, cwd='/path/to/project')
環境変数の不足
スクリプトによっては、subprocess環境に設定されていない環境変数に依存している場合があります。明示的に渡してください:
import os
env = os.environ.copy()
env['MY_VAR'] = 'value'
subprocess.run(['myscript.sh'], check=True, env=env)
アクセス拒否
スクリプトに実行権限がない場合、2つの方法があります。まず実行ビットを付与する方法:
subprocess.run(['chmod', '+x', 'myscript.sh'], check=True)
subprocess.run(['./myscript.sh'], check=True)
または、権限の問題を回避してインタープリタを直接呼び出す方法:
subprocess.run(['bash', 'myscript.sh'], check=True)
ステップ4 — check=Trueか手動チェックかを判断する
すべての失敗が例外を必要とするわけではありません。ゼロ以外の終了コードが正常な結果となる場合(接続確認やプロセスの死活監視など)は、returncodeを直接確認してください:
result = subprocess.run(['ping', '-c', '1', '8.8.8.8'], capture_output=True)
if result.returncode == 0:
print('Host is reachable')
else:
print('Host unreachable')
check=Trueは、失敗が実行を停止すべきコマンドに対してのみ使用してください。失敗が有効な結果となる場合は省略してください。
修正の確認
呼び出しを単独で実行し、終了コードが0であることを確認してください:
result = subprocess.run(
['your', 'command', 'here'],
capture_output=True,
text=True
)
print('Exit code:', result.returncode) # Should print: Exit code: 0
print(result.stdout)
終了コードが0であれば完了です。まだゼロ以外の場合はresult.stderrで次の手がかりを確認し、繰り返してください。
クイックリファレンス
- まずstderrをキャプチャする —
capture_output=True, text=Trueにより、実際の失敗原因が明らかになります - 重要なコマンドには
check=Trueを使用する — 失敗時に実行を停止すべき場合に使います - ゼロ以外の終了コードが想定内の結果の場合は
check=Trueを使わない shell=Trueと信頼できない入力を絶対に組み合わせない — 代わりに引数のリストを渡してください- まずターミナルでコマンドをテストする — 環境やPATHの問題を切り分けられます

