I was reviewing a scheduled run one morning when an agent that had worked fine the night before had stalled on a config file it simply could not read. Finder showed the file. The size was there. And still the agent kept reporting that the target file was empty.
It took me a while to see it. I keep my Dolice Labs working folder under Dropbox sync, and part of that folder had quietly turned into an "online-only" placeholder.
The same thing happens with iCloud Drive and OneDrive. If you run Antigravity across a cloud-synced folder, this is a trap you are likely to hit at least once. Let's walk through it.
Symptoms
First, what it actually looks like. Here is what I ran into.
| Situation | Observed behavior |
|---|---|
| Hand a file to the agent | Stops with "file is empty" or "cannot read contents" |
| Open the file in the editor | Blank for a moment, then the contents appear seconds later (or it won't open) |
| Finder / File Explorer | The file exists and shows a size |
| Workspace re-indexing | Runs constantly with no edits, CPU climbs |
The awkward part is that waiting sometimes fixes it. Reading the file triggers a download, and the next time it opens correctly. That "it works sometimes" behavior is exactly what delayed the diagnosis.
Reproduction conditions
The failure needs a few things to line up.
One, the working folder lives under cloud sync — Dropbox, iCloud Drive, OneDrive, or the desktop Google Drive client.
Two, the files in that folder are in an "online-only" state. To save disk space, only a lightweight placeholder with no real data stays on the machine, and the body is downloaded the moment the file is opened.
Three, the agent or editor reads the file before that download finishes. A placeholder reports its logical size, but physically it is still zero bytes. Read it there and it looks like an empty file.
On macOS, Dropbox and OneDrive both ride on the File Provider mechanism, so these "dataless files" are standard. Great for saving space, poor company for automation.
Root cause
The heart of it is this: what the filesystem shows and what data is actually on hand do not match.
ls returns metadata — logical size and modification time. A placeholder fills that in just fine. The real bytes, meanwhile, live only in the cloud. Only when a read arrives does the sync daemon start downloading, and until it completes the file has no contents.
Agents are fast, and they do not wait. Read into that download gap and you grab nothing. Worse, the sync daemon rewrites modification times, so Antigravity's file watcher decides "something changed" and re-indexes again and again. That was why the index kept running while I wasn't touching anything.
Solutions
1. Check whether the data is actually present
Start by separating the cases. Look past logical size and check whether the bytes are physically there.
# If the Blocks column (the leading number) is 0, it is a placeholder with no data yet
ls -ls path/to/config.json
# du reports blocks used. 0B means there are no local contents
du -h path/to/config.jsonIf ls -l shows a large size but du -h returns 0B, that is an online-only placeholder. Confirm this and the cause is all but settled.
2. Hydrate the data in place
One read is enough for File Provider to download the body. Hydrating the whole folder up front removes any window for the agent to grab an empty file.
# Hydrate a single file
cat path/to/config.json > /dev/null
# Hydrate the whole working tree first (skip heavy directories)
find . -type f \
-not -path './node_modules/*' -not -path './.git/*' -not -path './.next/*' \
-exec cat {} + > /dev/null 2>&1The sync app's UI does the same thing. In Dropbox, right-click the folder and choose "Make available offline"; under macOS File Provider, choose "Always Keep on This Device."
3. Keep active repositories out of the synced folder (recommended)
Rather than keep treating symptoms, I found it more reliable to design the problem away. These days I git clone the repositories I touch daily into a local-only directory like ~/dev and keep them out of cloud sync entirely.
Sync becomes the "distribution and backup layer," while the working tree is the "always-local layer." Once I split those two, the empty-file incidents stopped. Git already handles version history, so there was never much reason to lean on cloud sync for the working tree itself.
4. If you must work under sync
If circumstances force you to work inside a synced folder, at least exclude generated and dependency files from sync. Keeping node_modules, .next, and build output out of the synced set alone cuts re-indexing frequency and download waits considerably. This is the same instinct as separating build artifacts from sync that I described in why Antigravity agents break your Xcode build on a synced folder.
Prevention
A few habits I keep to avoid a repeat.
Before starting work on a new machine or folder, I run du -sh once to check whether the working tree holds real data. If it's near zero, it is still placeholders.
For unattended work like scheduled runs, I add a hydration step before the real reads. Fold the download wait inside the process and it won't stall on a grabbed blank.
Above all, keep the working tree outside the synced folder. Most of the uncanny behavior — an index that won't settle, an opened file that comes up empty — vanishes at that one point. For related symptoms, it helps to keep diagnosing a stalled Antigravity workspace index and a sync design for Settings Sync across two Macs nearby; they speed up the isolation.
An "empty file" error naturally makes you suspect the editor or the agent. This time the culprit sat one layer earlier, in the state of the filesystem. What you see and what you actually hold are not always the same thing, and cloud sync is where that quiet assumption breaks.
If you're stuck at the same spot, I hope this helps you isolate it. Thank you for reading.