「CLAUDE_CODE_PROCESS_WRAPPER」の起動エラー — Claude Code企業ランチャー
企業ランチャーを噛ませるCLAUDE_CODE_PROCESS_WRAPPERが原因でClaude Codeが起動しないときの、エラー文言別の切り分け方と契約違反の見つけ方をまとめます。
CLAUDE_CODE_PROCESS_WRAPPERは、企業が求める必須ランチャーを経由してClaude Codeの各プロセスを起動する仕組みです。値が使えないとき、Claude Codeはラップせずに起動するのではなく、そのプロセスの起動そのものを拒否します。エラーメッセージは変数名で始まり理由を続ける形式なので、まず文面から原因の見当がつきます。
起動しないときはclaude daemon statusから見る
エラーの出る場所はプロセスによって違います。見る順番は、まずシェルからclaude daemon statusを実行することです。Claude Code v2.1.287で、ホームと設定ディレクトリを空の一時ディレクトリに差し替え、変数だけ変えて実行すると次のようになります。
# 変数なし
claude daemon status
# => not running
# 実行権限のないファイルを指定
CLAUDE_CODE_PROCESS_WRAPPER=/tmp/work/noexec claude daemon status
# => not running
# => warning: CLAUDE_CODE_PROCESS_WRAPPER: launcher `/tmp/work/noexec` is not an executable regular file — background sessions will refuse to start rather than run unwrapped
# 存在しないパスを指定
CLAUDE_CODE_PROCESS_WRAPPER=/opt/corp/none claude daemon status
# => warning: CLAUDE_CODE_PROCESS_WRAPPER: launcher `/opt/corp/none` does not exist or is not readable — background sessions will refuse to start rather than run unwrapped
# `;`を含む値
CLAUDE_CODE_PROCESS_WRAPPER="/tmp/work/launcher; rm -rf x" claude daemon status
# => warning: CLAUDE_CODE_PROCESS_WRAPPER: the value contains an unquoted shell metacharacter (one of ; | & $ ( ) ` < >) — it is an argv list, not a shell command — background sessions will refuse to start rather than run unwrapped値が正しいときは警告の代わりに、launcher: (none running) — this claude resolves ...で始まる行が出ます。続きは「次のバックグラウンドサービスをそのランチャー経由で起動する」という内容です。JSON配列形式の値はlauncher --profile ccのように空白区切りに解決された形で表示されます。
警告が出なくなるまで値を直してから、実際のセッションを立ち上げる流れが安全です。
実際にセッションが落ちたときのメッセージは、症状ごとに表示先が違います。
症状ごとの表示先
値そのものが使えない
変数名で始まり、理由が続きます。例は
is not an executable regular fileです。execせずに終了する
開始しようとしたセッションが失敗し、エージェントビューの行がランチャー名を含む
must exec, not daemonizeを報告します。ランチャーが残した子プロセスは、バックグラウンドサービスが後から回収します。サービスに届かない
ランチャーの問題が
Couldn't reach the background service (...)の括弧の内側に理由として入ります。
ランチャースクリプトが満たすべき契約
エージェントビューの行がmust exec, not daemonizeで失敗する場合や、起動直後にセッションが落ちる場合は、次の契約を満たしているかを確かめます。
- 必ず
exec "$@"で終わる。子プロセスをforkして自分は終了するランチャーは、バックグラウンドサービスが追跡できない孤立プロセスを残します - 引数を並べ替えたり吸収したり先頭に追加したりしない。最初の引数がClaude Codeのバイナリで、それ以降が丸ごとargvです
- 継承した環境変数をすべて
execに渡す。認証情報の注入など変数を足すのは構いませんが、継承した変数を落としてはいけません。セッションごとの認証トークンやモデル選択、CLAUDE_CODE_PROCESS_WRAPPER自体もこの継承環境に乗っています。許可リストで環境を再構築するランチャーは、起動するセッションを壊し、/statusにランチャー不一致が出ます - 毎回の起動から3秒ほどで
execに到達する。バックグラウンドの初回ディスパッチはランチャーを最初の出力バイト前に2回連続で実行するため、シングルサインオンのような重い処理は遅延させるかキャッシュから読みます - 自分自身の内側から呼ばれることに耐える。Claude Codeはネストした自己再起動のすべてにランチャーを適用するため、排他リソースを取得するランチャーはすでに保持していることを検知する必要があります
- Claude Codeが起動する前に端末へ書き込まない。
execより前に出力した内容は、セッションが初期化前に落ちた場合クラッシュの原因として報告されます
サンドボックスのように環境をリセットする仕組みの内側へ入るランチャーは、継承した環境を内側で原文どおり再エクスポートします。最小のランチャーは次の形です。
#!/bin/sh
# 組織が必要とする処理(サンドボックス・ネットワーク制御・認証情報の注入)をここに書く
exec "$@"実行権限を付けるのを忘れると、前掲のとおりis not an executable regular fileの警告になります。
値の書き方と反映手順
値はランチャーの絶対パスが基本で、/opt/corp/launcherのような形式です。ランチャー自身に引数を渡すときはパスの後に続けます。空白がトークンを区切り、二重引用符で空白を含むトークンをまとめられます。[で始まる値はJSON文字列配列として読まれ、["/opt/corp/launcher", "--profile", "cc"]のように書けます。
シェル構文は使えません。変数展開やグロブは効かず、;・|・&・$(のようなクォートなしの演算子は設定エラーとして拒否されます。
ランチャーを入れて反映するまで
- 1
settingsのenvブロックに書く
シェルの
exportでは足りません。バックグラウンドサービスはシェルより長く生き残り、シェルのプロファイルを読み直さないからです。1台だけなら~/.claude/settings.json、組織に配るならmanaged settingsに同じブロックを入れます。{ "env": { "CLAUDE_CODE_PROCESS_WRAPPER": "/opt/corp/launcher" } } - 2
バックグラウンドサービスを止める
実行中のサービスと開いている
claudeセッションは、起動時に変数を一度だけ読みます。claude daemon stop --anyは、サービス本体に加えて、そのサービスが載せているバックグラウンドセッションも止めます。セッションを残したいときは--keep-workersを付けます。次にclaude agentsなどサービスを必要とするコマンドを実行すると、ラップされたサービスが立ち上がります。開いているセッションも再起動します。 - 3
反映を確かめる
/statusのSelf-exec欄に、解決された起動コマンドが出ます。実行中のサービスが設定と一致しないと、ここに警告が出ます。シェルからはclaude daemon statusが同じ情報を返します。変数を外した後でも、こちらなら確認できます。
手元で再起動できない端末では、設定を配った後に最初に起動したセッションが、ラップされていない古いオンデマンドサービスを自動で止めます。新しいセッションが一度も起動しない端末には、古いサービスが残ります。ユニットファイルでインストール済みのサービスは、この手順の再起動が常に必要です。
どのプロセスがラップされ、どれが外れるか
Claude Codeが自分のバイナリから起動するプロセスが対象です。企業が必須ランチャー経由の起動を求める背景には、そこでサンドボックスやネットワーク制御、認証情報の注入を適用させる方針があります。
対象は、バックグラウンドサービスと、エージェントビューの各行のターミナルホストおよびセッション(待機用を含む)です。アップデートや異常終了の後にサービスが再起動するセッションと、アップデート完了のための自己再起動も含まれます。加えて、Remote Controlが起動するセッションプロセスとagent teamsがtmux/iTerm2で開く分割ペインのセッションも対象で、この2つはv2.1.210以降が必要です。
claudeコマンドをPATH上でラップするタイプのランチャーは、サービスやその配下のセッションに届きません。バイナリの直接パスから起動し、claudeという名前の解決を経由しないからです。
対象外のプロセスは次の5つです。
- 設定前に書かれたユニットファイルで
launchd/systemdが起動する、インストール済みバックグラウンドサービス - ターミナルで自分で起動したセッション
claude-cli://ディープリンクが開く最初のプロセス--worktreeと--tmuxの組み合わせが開く再起動- Claude in Chromeのネイティブメッセージングホスト
v2.1.287のclaude daemon --helpには「Service install is disabled in this version」と出ます。続きは「デーモンはオンデマンドで動き、最後のクライアントが切れると終了する」という内容です。ユニットファイルで常駐させる構成だけは、--anyなしのclaude daemon stopで止めます。
ターミナルで自分で起動するセッションまでカバーするには、PATH上のclaudeより手前のディレクトリに、実バイナリを自分のランチャー経由で呼ぶスクリプトを置きます。管理されているシンボリックリンクは置き換えません。サービスとその配下のセッションはPATHを引かずに起動するため、2つのランチャーが重なることはありません。
ディープリンクの経路は、disableDeepLinkRegistration設定でハンドラーの登録を防ぐと完全に塞げます。
Windowsでは変数自体が無視されます。ランチャーの契約はexecを前提にしており、Windowsはこれをサポートしないためです。変数を設定しても全プロセスがラップされずに動き続け、デバッグログに警告が出るだけです。processWrapperキーもmacOSとLinux向けの設定です。ロールアウト計画では、Windows機をラップ対象外として数えます。
ラップされたヘルパープロセスは、psやアクティビティモニタでclaude bg-pty-hostやclaude bg-spareというラベルが出なくなります。ランチャーのexecが引数リストを組み直すためで、プロセスの中身は変わりません。
バージョンによって、エラーが出ないまま効かない
変数と設定キーでは、効き始めるバージョンが違います。
| 設定 | 対象 | 必要バージョン | 設定できる場所 |
|---|---|---|---|
CLAUDE_CODE_PROCESS_WRAPPER(環境変数) | 対象Claude Code自身が起動するプロセス全般 | 必要バージョンv2.1.208以降 | 設定できる場所envブロック(ユーザー設定 / managed settings) |
processWrapper(設定キー) | 対象同上。環境変数と同じ値を名前付きキーとして渡す | 必要バージョンv2.1.210以降 | 設定できる場所ユーザー設定 / managed settings |
claudeProcessWrapper(VS Code拡張) | 対象拡張機能がClaudeプロセスを起動する実行ファイル | 必要バージョン拡張機能側の設定 | 設定できる場所VS Code拡張の設定 |
v2.1.208より前は変数を無視し、すべてのプロセスをラップなしで起動します。processWrapperもv2.1.210より前は未知のキーとして無視され、ランチャーは適用されず、エラーも出ません。展開後はclaude daemon statusで、実行中のバージョンが設定を反映しているかを確かめます。
両方設定されていると環境変数側が優先されます。プロジェクト設定・ローカル設定ではどちらも設定できません。リポジトリにコミットされたファイルが、マシン上の全プロセスの前にバイナリを割り込ませられてはならないためです。.claude/settings.jsonと.claude/settings.local.jsonに書いた変数は、警告付きで無視されます。processWrapperキーはそもそも読まれません。
managed settingsの値は、ユーザー設定にもシェルのexportにも優先します。ユーザーが自分で別のランチャーを指すように変えることはできません。processWrapperをリモートのmanaged settingsで配ると、管理者が与える実行ファイルを走らせる他の設定と並んで、セキュリティ承認ダイアログに表示されます。
VS CodeのclaudeProcessWrapperは別の設定です。VS Code拡張の設定に書き、Claudeプロセスを起動する実行ファイルを指定します。ラップされたセットアップでは、拡張が設定と組み込みデフォルトの手順をスキップするため、会話はManualモードで始まります。例外は、initialPermissionModeを指定した場合と、以前の会話でモードを選んでいた場合です。
CLAUDE_CODE_SHELL_PREFIXとは渡し方が違う
似た名前の変数と、ランチャーの書き方が違います。
2つのラッパー変数
CLAUDE_CODE_PROCESS_WRAPPER
Claude Code自身のプロセスをラップします。コマンドは別々のargvトークンとしてランチャーのexecに渡ります。
CLAUDE_CODE_SHELL_PREFIX
Bashツール呼び出し・hooks・stdio型MCPサーバーの起動コマンドをラップします。それぞれが$1の中に1つのシェルクォート済み文字列として渡ります。
片方向けに書いたランチャーは、もう片方としては動きません。
よくあるつまずき
- 以前
~/.local/bin/claudeのシンボリックリンクを自作ランチャーで置き換えていた場合は、同じ変更で元のシンボリックリンクに戻します。置き換えたままだと、最初のラップされたセッションがバックグラウンドサービスを2つのランチャー経由で同時に起動します。さらにインストールが外部管理の状態になり、/doctorがそれを報告します。自動アップデートはそのファイルを置き換えず、古いバージョンの掃除も止まったままです - リポジトリの
.claude/settings.jsonに書いたのにラップされないときは、書き場所が原因です。プロジェクト設定とローカル設定の変数は警告付きで無視されるので、ユーザー設定かmanaged settingsに移します - 古いバージョンの端末だけランチャーを通らないときは、エラーが出ないので気づきにくい症状です。環境変数はv2.1.208以降、
processWrapperキーはv2.1.210以降が必要なので、まずclaude --versionを見ます
配布前の確認は、claude daemon statusの警告が消えるかどうかです。企業向けのネットワーク設定と併せて導入する場合は、ランチャーの契約を先に満たしておくと、起動しない原因の切り分けが片方で済みます。