Hermes で Too Many Open Files が出たが、問題はそれだけではなさそうだ

Hermes で Too Many Open Files が出たが、問題はそれだけではなさそうだ

目次

今日は Hermes / OpenClaw 側で起きた不具合をかなり追っていた。見た目は単純そうだったが、実際には一つのまっすぐな原因ではなかった。

最初に目についたキーワードは Too many open filesErrno 24 だった。こういうエラーを見ると、すぐに「fd limit が低すぎるのでは」「ulimitlaunchctl、plist を直せばいいのでは」と考えたくなる。

ただ、今日の調査はそこまで単純ではなかった。

Hermes open files debugging cover

最初に壊れたのは機能ではなくツール層だった

最初に目立った失敗は、特定の機能ではなくツール側に出ていた。

いくつかの cron 実行、検索、terminal 呼び出しが、本格的に動く前に次のエラーで落ちていた。

OSError: [Errno 24] Too many open files

この種のエラーが、検索、terminal、定期実行のような無関係に見える場所へ同時に出始めると、調査の視点は「このコマンドが壊れている」では足りなくなる。実行環境全体のリソース・ライフサイクルを疑うべき段階に入る。

そこで疑う対象は一つではない。

  • 長寿命プロセスが fd を積み上げていないか
  • sandbox や worker の掃除が遅れていないか
  • gateway が重複起動していないか
  • skill scan、ログ、subprocess pipe が残っていないか
  • そもそもの fd limit が低すぎないか

つまり、ulimit -n を上げるだけでは圧力は減るかもしれないが、何が起きたかの説明にはまだ足りない。

現場の数字だけを見ると「今まさに枯渇している」とは言い切れなかった

次にやるべきことは、limit と関連プロセスの fd 数を確認することだった。

まず見えた数字はこうだった。

ulimit -n = 1024

1024 は十分に大きいとは言わないが、見た瞬間に「これでは必ず壊れる」と断定できるほど低いわけでもない。

さらに、その時点で見えた fd 数も極端ではなかった。

  • Hermes 関連プロセスが約 97
  • gateway 関連の Python プロセスが約 91

その瞬間のスナップショットだけを見るなら、「今この場で fd が完全に枯渇している」とまでは言いにくかった。

ここで最初の引っかかりが出た。ログでは Too many open files が強く出ているのに、現場で測った数字はその結論をまっすぐには支えていなかった。

むしろ説明として自然なのは次の三つだった。

  1. 以前に fd 圧力があり、ピークはすでに過ぎていた
  2. 局所的な burst、短命な子プロセス、古い状態が間接的に壊した
  3. Too many open files は表面症状で、今の起動失敗を直接止めている原因は別に移っていた

調査を進めるほど、今回は三番目に近く見えた。

いちばん怖いログ行が、いまの主因とは限らない

ログを追うと、たしかにかなり強い警告が出ていた。

[Errno 24] Too many open files: '/Users/yougikou/.hermes/config.yaml'

これを見ると、「設定ファイルすら開けないのだから、答えは fd しかない」と言いたくなる。

しかしスタックをさらに読むと、実際に gateway の起動を止めていたのは別の、もっと具体的なエラーだった。

NameError: name 'ensure_open_file_limit' is not defined

これで問題の見え方が変わった。

つまり、たとえ過去のどこかで Too many open files が本当に起きていたとしても、その時点で gateway が起動しなかった直接原因は fd 枯渇ではなかった。直接の原因は、エントリポイントが ensure_open_file_limit() を呼んでいるのに、その import が正しく入っていなかったことだった。

言い換えると、先にリソース圧力があり、そのあとに現場を掴んだ時点では、起動を止めるドミノの先頭が import バグに置き換わっていた可能性が高い。

この点は覚えておきたい。ログの中でいちばん頻繁に出てくるエラーが、いまの故障面に最も近いエラーとは限らない。

plist、launchctl、常駐サービスも無関係ではない

問題がややこしくなった理由の一つは、Hermes の動き方そのものにある。

このマシンでは二つの LaunchAgent が見つかった。

  • ai.hermes.gateway
  • ai.openclaw.gateway

そして、それぞれに対応するバックグラウンドプロセスも見えていた。

たとえ完全に同じ実行経路ではなくても、少なくとも近い gateway / agent 系サービスが二系統あるということになる。そうなると、リソース消費、重複接続、古いプロセス、混ざったログが、誰が fd 圧力を生んでいるのかを見えにくくする。

さらにログには別のノイズもあった。

  • Discord bot token が別プロセスですでに使われていた
  • Discord privileged intents の設定も不十分だった

どちらも Too many open files そのものではない。だが、サービスが起動、再試行、失敗、再接続を繰り返す状態を生みやすくする。その結果、失敗した起動サイクルがソケットや fd の寿命を引き延ばしているのではないか、と疑いたくなる。

まだそこまで証明できてはいない。ただ、「limit を上げれば終わり」と考えるよりは、現実のシステムの壊れ方に近い仮説だと思っている。

今日学んだのは、limit の上げ方ではなかった

操作の一覧だけを書けば、やることはおなじみのものばかりだ。

  • ulimit -n を確認する
  • launchctl 配下のサービスを見る
  • LaunchAgent の plist を読む
  • gateway の stdout / stderr ログを見る
  • プロセスの fd 数を数える
  • gateway の重複起動を除外する

ただ、今日いちばん大きかったのは手順表そのものではなく、判断の順番だった。

まず本当にリソース問題なのかを確認する。次に、それが今もリソース問題なのかを確認する。そのうえで初めて、システム設定を変えるべきかを考える。

これは当たり前に見えて、実際には逆にやりやすい。Errno 24 を見た瞬間に「原因は limit が低いことだ」と決めてしまうと、その後の情報を全部その結論の補強として読んでしまう。

でも今日の状況では、ログの文言、現場の fd 数、gateway の現在のクラッシュ地点は、きれいには一致していなかった。

関係はある。だが同じではない。

今の時点での見立て

今日時点では、これは単一のバグというより複合故障に見える。

  • 一部は fd 圧力や掃除の遅れに見える
  • 一部は常駐サービスの重複や再起動経路の混乱に見える
  • さらに一部は fd とは直接関係のない、明確なエントリポイントのバグだった

だから今の Too many open files は、完成した診断名というより症状ラベルに近い。

NameError を直せば改善するかもしれない。fd limit や plist を調整すれば、再現しにくくなるかもしれない。だが、どちらも単独では根因を掴んだ証明にはならない。

まだ結論が出ていない部分:plist をどう変えるべきか

次に本当に検証したいのは、macOS の LaunchAgent plist を変えるべきなのか、変えるならどう変えるべきか、という点だ。

自然な仮説はある。launchd から起動したサービスの fd limit が対話シェルより低い、あるいは実効上の制限が違っているなら、plist に適切な変更を入れることで発生確率を下げられるかもしれない。

ただし、ここにはまだ最終結論がない。

いま手元にある証拠だけでは、plist の変更が正しい方向だと断定するには足りないし、どの変更方法が信頼できるのかを言い切るにも足りない。

なので今日はここで止めておく。Too many open files は確かに主役に見えるが、おそらくそれだけではない。plist をどう書き換えるべきか、そしてその変更で本当に安定するのかについては、まだ調査と検証を続けている段階だ。いまあるのは推測であって、結論ではない。

共有 :
comments powered by Disqus