朝、スケジュール実行の記録を確認していたときのことです。前夜まで問題なく動いていたはずのエージェントが、設定ファイルを読めずに止まっていました。Finder を開くとファイルはそこにあります。サイズも表示されています。それなのにエージェントは「対象ファイルが空です」と繰り返す。
原因にたどり着くまで、しばらく手が止まりました。私は個人開発で Dolice Labs の複数サイトを運用しており、その作業フォルダを Dropbox の同期下に置いています。そのフォルダの一部が、いつの間にか「オンラインのみ」のプレースホルダーに変わっていたのです。
同じ症状は iCloud Drive や OneDrive でも起こります。クラウド同期を挟んで Antigravity を使っている方には、一度は踏みうる落とし穴だと思います。順番に見ていきます。
症状
まず、どんな見え方をするのかを整理します。私が実際に遭遇したのは次のようなケースでした。
| 状況 | 観測された挙動 |
|---|---|
| エージェントにファイルを渡す | 「ファイルが空です」または「内容を取得できません」で停止 |
| エディタでファイルを開く | 一瞬だけ空白 → 数秒後に中身が現れる(または開けない) |
| Finder / エクスプローラー | ファイルは存在し、サイズも表示されている |
| ワークスペースの再インデックス | 作業していないのに頻繁に走り、CPU が上がる |
厄介なのは、しばらく待つと直ることがある点です。読み出したタイミングで実体がダウンロードされ、次に開くと正常に見える。この「時々直る」ふるまいが、原因の特定を遅らせました。
再現条件
次の条件が重なると発生します。
ひとつ、作業フォルダがクラウド同期の配下にあること。Dropbox、iCloud Drive、OneDrive、Google ドライブのデスクトップ版が該当します。
ふたつ、そのフォルダのファイルが「オンラインのみ(online-only)」の状態にあること。ディスク容量を節約するため、実体を持たない軽量なプレースホルダーだけがローカルに残り、開いた瞬間に本体をダウンロードする仕組みです。
みっつ、エージェントやエディタが、実体のダウンロードが終わる前にファイルを読みにいくこと。プレースホルダーは論理サイズこそ表示しますが、物理的にはまだ 0 バイトです。ここを読むと「空のファイル」に見えます。
macOS では Dropbox や OneDrive も File Provider の仕組みに乗っており、この「実体を持たないファイル(dataless file)」が標準的に使われます。省スペースには有効ですが、自動化とは相性が悪いのです。
原因
核心は、ファイルシステム上の見かけと、実際に手元にあるデータが一致していないことです。
ls はメタデータ(論理サイズ・更新日時)を返します。プレースホルダーでもここは埋まっています。一方で、実体はクラウド側にしかありません。読み出し要求が来て初めて同期デーモンがダウンロードを始め、完了するまでの間、そのファイルは中身のない状態です。
エージェントの処理は速く、しかも待ってくれません。ダウンロードの隙間に読みにいけば空を掴みます。さらに悪いことに、同期デーモンはファイルの更新日時を書き換えるため、Antigravity のファイル監視が「変更あり」と判断し、再インデックスを繰り返します。作業していないのにインデックスが走り続けるのは、これが理由でした。
解決策
1. 実体を持っているかを確認する
まず切り分けです。論理サイズではなく、物理的にデータを持っているかを見ます。
# Blocks 列(先頭の数値)が 0 なら、まだ実体がないプレースホルダー
ls -ls path/to/config.json
# du はブロック使用量を返す。0B ならローカルに中身がない
du -h path/to/config.jsonls -l のサイズは大きいのに du -h が 0B を返したら、それはオンラインオンリーのプレースホルダーです。ここが確認できれば、原因はほぼ確定です。
2. その場で実体を取得する
一度読み出せば、File Provider が本体をダウンロードします。フォルダごと先に実体化しておくと、エージェントが空を掴む余地がなくなります。
# 単一ファイルを実体化
cat path/to/config.json > /dev/null
# 作業ツリー全体を先に実体化(node_modules 等の重量物は除外)
find . -type f \
-not -path './node_modules/*' -not -path './.git/*' -not -path './.next/*' \
-exec cat {} + > /dev/null 2>&1同期アプリの UI からも同じことができます。Dropbox なら対象フォルダを右クリックして「ローカルにする(Make available offline)」、macOS の File Provider 管理下なら「このデバイスに常にダウンロード」を選びます。
3. アクティブなリポジトリは同期フォルダの外に置く(推奨)
対症療法を続けるより、設計で断つほうが確実でした。私は現在、日々コードを触るリポジトリを ~/dev のようなローカル専用ディレクトリに git clone し、クラウド同期の対象から外しています。
同期は「配布・バックアップの層」、作業ツリーは「常にローカルにある層」。この二層を分けてから、エージェントが空ファイルを掴む事故は起きなくなりました。バージョン管理は Git が担うので、作業ツリーそのものをクラウド同期に頼る理由は、もともと薄いのです。
4. どうしても同期下で作業する場合
事情があって同期フォルダ内で作業するなら、少なくとも生成物と依存物は同期から除外します。node_modules・.next・ビルド成果物を同期対象から外すだけでも、再インデックスの頻度とダウンロード待ちは大きく減ります。この考え方は、Dropbox 同期フォルダで Antigravity に Xcode を任せるとビルドが壊れる理由でも触れた、ビルド成果物を同期から切り離す発想と同じです。
予防策
再発を防ぐために、私が習慣にしていることを挙げます。
新しいマシンや新しいフォルダで作業を始める前に、du -sh で作業ツリーが実体を持っているかを一度確認します。0 に近ければ、まだプレースホルダーです。
スケジュール実行のように無人で走らせる処理では、本番の読み出しの前に実体化のステップを一段挟みます。ダウンロード待ちを処理の内側に取り込んでおけば、空掴みで止まることはありません。
そして何より、作業ツリーは同期フォルダの外に置く。インデックスが止まらない、開いたファイルが空になる、といった不可解な挙動の多くは、この一点で消えます。似た系統の症状として、Antigravity の Workspace Indexing が止まる時の診断手順や、複数 Mac をまたぐ Settings Sync の運用設計もあわせて見ておくと、切り分けが速くなると思います。
「ファイルが空」というエラーは、ふつうエディタやエージェントを疑いたくなります。けれど今回の犯人は、その手前のファイルシステムの状態でした。見えているものと、手元にあるものは、必ずしも同じではない。クラウド同期を挟むと、その当たり前が崩れます。
同じ場所で立ち止まっている方の、切り分けの一助になれば幸いです。お読みいただきありがとうございました。