Codexが
「Operation not permitted」で
起動しない

  • Codex CLIが Error: Operation not permitted (os error 1) を出して起動しなくなりました。設定を疑いましたが、同じディレクトリで ls を打ったらこちらも同じエラーでした。
  • os error 1はEPERMで、「ファイルがない」ではなく「触らせない」という意味です。macOSは書類フォルダやダウンロードフォルダへのアクセスをアプリ単位で制限しています。
  • カレントディレクトリを変える、絶対パスで指定する、別のターミナルで開く。条件を一つずつ変えると、どの層で止まっているかが絞れます。
  • 今回はWezTermを再起動したら直りました。同じ症状は他の環境でも報告されていて、確実な回復手段が再起動しかない状態です。

関連記事

1. Codexのエラーだと思ったら、lsも動かなかった

1. Codexのエラーだと思ったら、lsも動かなかった

Codexで作業を再開しようと codex resume と打ったら、こう返ってきました1

~/D/p/sample-app % codex resume
Error: Operation not permitted (os error 1)
Code language: JavaScript (javascript)

セッションの履歴が壊れたのかと思って、引数なしの codex も試しました。 起動画面の枠は表示されるのに、model と directory が loading のまま止まって、同じ一行が出て終わり。

╭───────────────────────────────────────╮
│ >_ OpenAI Codex (v0.149.1)            │
│                                       │
│ model:     loading   /model to change │
│ directory: loading                    │
╰───────────────────────────────────────╯
› Error: Operation not permitted (os error 1)
Code language: JavaScript (javascript)

directory が loading で止まっているのが引っかかりました。 作業ディレクトリを読もうとして失敗しているように見えます。 それで ls を打ってみたら、これでした。

~/D/p/sample-app % ls
ls: .: Operation not permitted
Code language: JavaScript (javascript)

Codexの設定を一時間くらい掘るところでした。

2. os error 1は「見つからない」ではなく「触らせない」

2.1. EPERMとENOENTは別のエラー

Unix系のシステムコールが失敗すると、errnoという番号で理由が返ります。 1番がEPERM(Error: operation not PERMitted:許可されていない操作)で、2番がENOENT(Error: NO such ENTry:そんな項目はない)2。 Rustで書かれたプログラムはこれを os error 1 の形でそのまま見せることがあります3

この二つは似た場面で出ますが、意味が違います。 ENOENTは、探した場所にファイルがなかった。 EPERMは、ファイルはあるが、あなたには触らせない4

つまり Operation not permitted が出た時点で、パスの綴りやインストールの失敗は容疑者から外れます。 存在は確認できているわけですから。 残るのは、誰が、何に対して、どういう権限で触ろうとしたのかという話だけです。

2.2. macOSがDocumentsやDownloadsを見張っている

権限といっても、chmod で見える読み書き実行のビットだけではありません。 macOSにはTCC(Transparency, Consent and Control:透明性、同意、制御)という仕組みがあって、書類フォルダやダウンロードフォルダ、デスクトップ、外付けボリュームへのアクセスをアプリ単位で管理しています5。 ファイルのパーミッションが drwxr-xr-x で自分が所有者でも、アプリに許可がなければEPERMで弾かれます6

今回のディレクトリは ~/Documents/projects/sample-app でした。 プロンプトでは ~/D/p/sample-app と省略されて表示されるので気づきにくいのですが、Documentsの配下です。 TCCの対象そのもの。

USBメモリや外付けSSDでも同じことが起きます。 Finderからは中身が見えるのに、ターミナルから ls /Volumes/BACKUP/ すると Operation not permitted になる7。 システム設定のプライバシーとセキュリティにあるフルディスクアクセスに、使っているターミナルアプリを追加して起動し直すと通るようになります8

3. 犯人を絞るには、条件を一つずつ変える

3.1. ディレクトリを変える、パスの指定を変える

ls が動かないとわかった時点で、疑うべき対象がCodexからターミナル全体に広がりました。 ここからは、変数を一つずつ動かして切り分けます。

最初に cd ~ してから ls。 ホームディレクトリで動くなら、権限がディレクトリ単位で落ちていることになります。 アカウント全体やターミナルアプリ全体が死んでいるわけではない。

次に、ホームにいる状態から絶対パスで ls -ld ~/Documents/projects/sample-app と指定します。 絶対パスなら見えるのに、そこに cd した状態だけ失敗するなら、シェルが握っているカレントディレクトリのハンドルが無効になっている可能性があります。 プロセスは開いたディレクトリをファイル記述子として保持していて、これが何らかの理由で使えなくなると、相対パスの基準点そのものが消えます。 タブを閉じて開き直し、cd し直すと戻ります。

3.2. アプリを変える、設定ファイルの所有者を見る

もう一つの軸が、アプリを変えることです。 WezTermで駄目でもiTerm2やターミナル.appなら動くなら、TCCの許可がアプリ単位で与えられていることの裏返しになります。 アプリのバンドルIDごとに許可が記録されているので、片方だけ通るのは普通にあり得ます。

Codex固有の可能性も一応つぶしておきます。 ls は通るのにCodexだけ落ちるなら、ls -ld ~/.codex ~/.codex/sessions で所有者を確認します。 ここが root になっていたら、過去に sudo でCodexを起動した痕跡です。 sudo chown -R $(whoami) ~/.codex で自分に戻せば直ります9

今回は ls の時点で落ちていたので、この線は最初から消えていました。 エラーを出したのがCodexでも、原因はCodexの外側にある。

4. 再起動で直る、という不具合が実在する

結局、WezTermを終了して起動し直したら、何事もなかったかのように戻りました。

~/D/p/sample-app % ls
README.md       Sources         Tests           docs            scripts
Code language: JavaScript (javascript)
4. 再起動で直る、という不具合が実在する

Codexも directory: ~/Documents/projects/sample-app を正しく表示して起動しました。 フルディスクアクセスの設定は何も触っていません。

同じ症状は他の環境でも報告されています。 しばらく作業したあとに突然 ls すら Operation not permitted を返し、ホームディレクトリでは動き、別のターミナルアプリなら動き、再起動すれば戻る10。 ディスクへのアクセス許可は与えてあるし、直前まで問題なく動いていた、という報告のされ方も今回と重なります。 数日おきに再発するという声もあって、作業中のセッションを全部畳んで再起動するのは、それなりに痛い。

エラーメッセージを出したプログラムと、原因のあるレイヤーは一致するとは限りません。 Codexが吐いたエラーだからCodexを調べる、という素直な進み方をしていたら、たぶんまだ ~/.codex の中を眺めていたはずです。 ls という、いちばん単純で疑う余地のなさそうなコマンドを打ってみたのが、結果的には近道でした。 壊れていないはずのものを一つ試してみる。 それだけで、探す範囲が半分になることがあります。

  1. codex resumeは、引数なしで実行すると過去のセッション一覧から選ぶピッカーが開き、–lastを付けると直近のセッションにそのまま入ります。セッションの記録は ~/.codex/sessions 以下にJSON Lines形式で保存されています。 – Codex Resume: Continue Your Last Session
  2. errno.hで定義されるマクロの一覧では、EPERMが1、ENOENTが2、ESRCHが3と続きます。値と名前の対応はPOSIXで定められています。 – Errno.h – Wikipedia
  3. Rustの標準ライブラリでは、OSが返したエラー番号をstd::io::Errorが保持し、raw_os_errorで取り出せます。表示時にはこの番号がそのまま文字列に含まれるため、os error 1のような形になります。 – std::io::Error – Rust
  4. GNU Cライブラリのマニュアルは、EPERMを、そのファイルや資源の所有者か特別な権限を持つプロセスだけが実行できる操作だと説明しています。ENOENTのほうは、存在するはずの場所にファイルがなかったという意味です。 – Error Codes (The GNU C Library)
  5. Appleは、macOS 10.15以降、DocumentsやDownloads、デスクトップ、iCloud Drive、ネットワークボリューム内のファイルにアプリがアクセスする前に、利用者の同意を得ることをシステム側で強制していると説明しています。 – Controlling app access to files in macOS – Apple Support
  6. 許可のないフォルダにアクセスすると、確認ダイアログすら出ずにOperation not permittedが返る場合があります。TCCの管理データベースが置かれた ~/Library/Application Support/com.apple.TCC がその例です。 – Every unsandboxed app has Full Disk Access if Terminal does
  7. macOS Sequoiaへのアップグレード後、USBメモリ上のファイルに対してlsがOperation not permitted (os error 1)を返すようになり、ターミナルアプリにフルディスクアクセスを与えて再起動したら解決した、という報告があります。 – OSX Sequoia & Operation not permitted (os error 1)
  8. フルディスクアクセスの一覧は、システム設定のプライバシーとセキュリティから開き、左下の+ボタンでアプリを追加します。設定を反映させるには、対象のアプリを一度終了して起動し直す必要があります。 – Full Disk Access – what is it and what does it do?
  9. Codexは、セッションファイルにアクセスできないとき、sudoで作られたのなら所有権を戻すよう案内するエラーを出すことがあります。案内される復旧コマンドがsudo chown -R $(whoami) ~/.codex です。 – Codex CLI is detected in setup but generation fails because Codex cannot access ~/.codex runtime state
  10. macOS上で、新しいターミナルを開いてlsを打つとOperation not permittedになり、codexも同じエラーで起動しない、しかしホームディレクトリに移動すると復旧する、という報告があります。ディスクへのアクセス権は与えてあり、iTermなら動く、確実に直るのは再起動だけ、という内容です。 – Claude creating file limit filesystem bug on long or many sessions