Claude CodeのHomebrewアップグレード後にバックグラウンドセッションが落ちるとき
brew upgrade --caskの直後にバックグラウンドセッションが全部止まる症状を、daemon.logのENOENTから見分け、claude --resumeで戻す手順と更新前の運用をまとめます。
Homebrewのcaskをアップグレードした直後、claude agentsの一覧には残っているのにバックグラウンドセッションが開かない。そんなときは、Claude Codeのバックグラウンドサービス(daemon)が自分で再起動しようとして失敗している可能性があります。~/.claude/daemon.logにupgrade self-respawn failed to spawn: ENOENTと出ていれば、この症状です。
会話の記録は残っています。claude --resume <セッションID>で戻せます。以下、見分け方と復旧、更新前の運用を順に説明します。
ENOENTが出る仕組み
GitHubのissue #84827は、claude-code@latestのcaskをアップグレードしたときに起きる失敗を報告しています。流れは次のとおりです。
アップグレードからセッション喪失まで
- 1
Homebrewがリンクを張り替える
/opt/homebrew/bin/claudeが新バージョンを指すようになります。 - 2
旧バージョンのファイルが消える
Caskroom配下の旧バージョンのディレクトリが削除されます。
- 3
daemonが自分のバイナリの消失に気づく
起動時のパスにあったバイナリがなくなったので、更新のために終了して再起動しようとします。
- 4
再起動が失敗する
再起動先が、起動時と同じバージョン付きのパスです。そのパスは既に無く、
posix_spawnがENOENTで失敗します。 - 5
配下のセッションが失われる
daemonが終了し、再起動もされないので、配下のワーカーは約60秒後に孤児として回収されることがあります。
報告者のログでは、削除を検知する行、終了する行、再起動に失敗する行が数百ミリ秒のうちに並んでいます。
[supervisor] binary at /opt/homebrew/Caskroom/claude-code@latest/2.1.223/claude was deleted ... — exiting for upgrade
[supervisor] shutting down (cause=upgrade, uptime=66788s, leases=4, live_workers=2)
[supervisor] upgrade self-respawn failed to spawn: ENOENT: no such file or directory, posix_spawn '/opt/homebrew/Caskroom/claude-code@latest/2.1.223/claude' — bg workers may be orphan-reaped ~60s after this process exits unless a client restarts the daemon (run `claude agents`)注目点は、失敗した行が指すのが旧バージョンのパスだということです。Homebrewはリンクの張り替えを先に行い、旧バージョンの削除を後に回すため、/opt/homebrew/bin/claudeは更新の瞬間から有効でした。daemonはその道を使っていません。
毎回起きるわけではない
同じissueには、アップグレードをきっかけにdaemonが止まったのに、再起動の失敗行が出ていない回も挙げられています(2026-07-01、バージョン2.1.196)。再起動が間に合った回があるということで、タイミング次第で成否が分かれる失敗です。「前回は無事だったから今回も大丈夫」とは言えません。
Homebrewに限った話ではない
メンテナーはこのissueへのコメントで、Linuxでも同じ手順で再現したと書いています。バージョン付きのパスに置いたバイナリと、そこを指す固定のシンボリックリンクを用意し、リンクの向き先を変えて旧ディレクトリを消すと、同じログが出たそうです。つまり原因はHomebrewそのものではなく、「アップグレードが旧パスを消す導入方式」と「daemonが起動時のパスを再利用する挙動」の組み合わせにあります。
自分の環境で起きたかを調べる
症状は静かに進みます。通知は出ません。次の順に見ると、原因を絞れます。
grep -n "self-respawn failed\|bg adopt" ~/.claude/daemon.log | tail
claude daemon status
ls -l /opt/homebrew/bin/claude| 見るもの | 該当するときの表示 | 意味 |
|---|---|---|
daemon.logのself-respawn failed to spawn: ENOENT | 該当するときの表示旧バージョンのCaskroomパスが書かれている | 意味この記事の症状 |
daemon.logのbg adopt: adopted=0 respawned=0 dead=N | 該当するときの表示deadが1以上 | 意味次のdaemon起動時に、ワーカーが生きていなかったと確認された |
claude daemon status | 該当するときの表示到達できない、またはバージョン不一致の警告 | 意味daemonが止まっている、または旧バージョンのまま |
ls -l /opt/homebrew/bin/claude | 該当するときの表示新バージョンのCaskroomパスを指す | 意味新しい本体は正常に入っている |
agent viewの側では、一覧に行は残ります。開くとSession is startingの表示のまま進まず、いつまでも続きます。報告者によれば、何度つなぎ直しても変わらず、ターミナルがrawモードのまま残ることもあるそうです。ソケットは残っているのに、裏にプロセスがいないためです。
落ちたセッションを戻す
issueのコメントとagent viewの説明から、戻し方は2段階です。
claude agentsを実行して、daemonを起動し直します。ログの警告文にも同じ案内が出ています。- 開かないセッションは
claude --resume <セッションID>で会話を再開します。会話の記録は残っています。
claude agents
claude --resume <セッションID>claude --resumeは、実行中だったプロセスの続きではありません。保存された会話を新しいプロセスで開き直すものです。途中だったコマンドや、メモリ上にしかなかった状態は戻りません。
agent viewの説明にあるclaude respawn <id>は別の操作です。保存された会話を探し、無ければ元のプロンプトを再実行します。既に動いた作業をもう一度走らせたくないときは、先に--resumeを試すほうが安全です。respawnと空の会話の関係は「no saved transcript」の対処に書きました。
一覧の行が残ったとき
死んだセッションの行が一覧から消えない、という別のissue(#77683)も関連として挙げられています。不要な行はCtrl+Xを2回、またはシェルからclaude rm <id>で消せます。会話の記録は残り、claude --resumeで開けます。
更新前にやっておく運用
issueが指す失敗は、アップグレード時にdaemonが動いていて、配下にセッションがある場合に起きます。次の3点で、被害を小さくできます。
- アップグレードの前に
claude agentsで一覧を見て、走っているセッションの終わりを待つ - 待てないときは、
claude daemon stop --anyでdaemonを自分から止めてからbrew upgradeを実行する(配下のセッションは止まりますが、会話の記録は残ります) - アップグレードが終わったら、
claude agentsで新しいdaemonを起動する
2つ目の手順は、公式のdocsに載っているコマンドを更新前に使うという運用上の提案です。issueで試された回避策ではありません。--keep-workersを付けて旧バージョンのワーカーを残したまま更新したときの挙動は、agent viewのページにもissueにも書かれていません。
放置されたアップグレードにも注意が要ります。報告者の3件は、いずれも手元で操作していない間のアップグレード直後でした。無人で更新が走る仕組みを使っているなら、更新の時刻とdaemon.logの時刻を突き合わせると、被害のあった回が分かります。
自動更新の変数を使っているとき
Homebrewでは、CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATEを1にすると、新しいバージョンがあるときにClaude Code自身がバックグラウンドで更新コマンドを実行します。更新の手段は同じbrew upgradeなので、daemonが動いているところに旧パスの削除が起きる条件は変わらないはずです。この点はdocsにもissueにも書かれていないため、筆者の推測です。この変数を使っていて症状に当たったら、更新前の確認が自動では挟まらない点を踏まえて、上の復旧手順を手元に置いておくと安心です。
直る見込みはあるのか
issueでは、再起動のたびに起動時のパスを使い回すのではなく、再起動の時点で/opt/homebrew/bin/claudeのような固定の起動パスを探し直し、失敗したらもう一度試す案が出ています。メンテナーは、この原因の分析と方向性は正しいと述べ、修正の対象としてフラグを立てました。
changelogを見ると、バージョン2.1.290に「Homebrewのアップグレード後にclaude agentsが『Couldn't restart the background service』で失敗し、バックグラウンドセッションが止まる問題を修正」という項目があります。末尾に「次のアップグレードから有効になる」旨の注記が付いています。
この項目がissue #84827の修正かどうかは、changelogにissue番号がないので断定できません。症状は近い、というところまでです。注記の意味は、2.1.290より前のバージョンが動いているdaemonは、更新の手順を自分では直せないということでしょう。2.1.290に上げる1回目のアップグレードは、旧コードのdaemonが引き受けるので、同じ失敗が起きることがあると読めます。次回のアップグレードから、新しいコードで防がれる想定です。この読みは筆者の解釈で、docsに明記はありません。
そのため、2.1.290以降への最初の更新だけは、上の運用を挟むと被害を避けやすくなります。
ほかの症状との見分け方
バックグラウンドセッションの不調は、見た目が似たものがいくつかあります。
| 症状 | 見るべき場所 |
|---|---|
Session is startingのまま進まず、daemon.logにENOENT | 見るべき場所本稿。daemonの再起動失敗 |
claude attachがThis session has no saved transcript | 見るべき場所最初の応答前にバックグラウンド化された会話。対処の記事 |
background service did not respond | 見るべき場所daemonが固まっている。claude daemon stop --any --keep-workersで入れ替える |
再起動やシャットダウンの後にfailedと出る | 見るべき場所マシンの停止が原因。48時間以内ならattachで再開する |
セッションの状態をスクリプトから読みたいときは、claude agents --jsonでバックグラウンドセッションを操作するが使えます。daemonの到達性まで見たい場合は、claude daemon statusが先です。
Homebrew以外の導入方式ではどうか
Homebrewは自動更新しない導入方式で、更新は手動のコマンドか、上の環境変数で行います。ネイティブインストーラーは自動更新しますが、docsの説明では、更新後にdaemonが自分で新バージョンへ移ります。起動時のパスをどう扱うかはdocsに書かれていません。メンテナーの再現がLinuxだったことを見ると、バージョン付きのパスを持つ導入方式では同じ形の問題が起きることがある、と考えておくのが現実的です。導入方式ごとの更新の違いはHomebrew・npm・ネイティブ導入の比較に、Macでの選び方はMacインストールの記事にあります。
まとめ
アップグレード後にバックグラウンドセッションが開かなくなったら、まずdaemon.logでself-respawn failed to spawn: ENOENTを探します。見つかれば、claude agentsでdaemonを起こし、claude --resumeで会話を戻します。会話の記録は失われていません。
これからの更新では、動いているセッションがないことを確かめ、必要ならdaemonを自分で止めてからアップグレードする運用が、被害を避ける実用的な手です。バージョン2.1.290の修正項目は、効き始めるのが更新の1回後という注記つきなので、その1回目をどう乗り切るかが当面の分かれ目です。