I started an Android build and it stopped with an error I had not seen before: duplicate resources. I had not added any resources. The project had built fine the night before, and I had not touched a single line since.
Following the path in the error, I opened the build folder and found the same file names repeated dozens of times, each with "conflicted copy" tacked onto the end. I counted. There were more than 80.
If you keep a project under Dropbox as an indie developer, you may meet the same morning. I did.
The short answer: files that are rebuilt every time don't get along with sync
The first thing I want to say is that it was not a bug in my code.
One of the crash-analysis tooling files is regenerated on every build, written back to the same path each time. Dropbox picked it up mid-write, and every collision between the build and the sync left behind another "conflicted copy."
Gradle treats those copies as resources too. It finds several with the same ID and stops at "duplicate." That is the whole story.
The unhelpful part is that the error never mentions Dropbox. When something says "duplicate," you suspect your own code first. I spent the first half hour removing recently added images one by one, which was the wrong place to look.
Triage starts with counting file names
My order of suspicion now has three steps.
- Open the parent folder of the path in the error and look for repeated names
- Search for "conflicted copy" in file names
- If they exist, check whether that folder is being synced
Step two is one line in a terminal.
# Count conflicted copies from the project root
# English locales use "conflicted copy"; Japanese locales use "競合コピー"
find . \( -name "*conflicted copy*" -o -name "*競合コピー*" \) | wc -lMine said 80-something. One or two could be a coincidence. Two digits means the setup itself is the problem.
The fix: stop syncing first, clean up second
Order matters. If you clean first, the copies come right back, so take the folders out of sync before deleting anything.
Dropbox's help center documents how to ignore a file or folder. On macOS with the Apple File Provider integration, the command looks like this.
# Take build output out of Dropbox sync (macOS with File Provider)
xattr -w 'com.apple.fileprovider.ignore#P' 1 "$HOME/Library/CloudStorage/Dropbox/Projects/MyApp/app/build"
xattr -w 'com.apple.fileprovider.ignore#P' 1 "$HOME/Library/CloudStorage/Dropbox/Projects/MyApp/.gradle"Without File Provider, the older attribute is com.dropbox.ignored. For Windows and Linux, and for the exact syntax, check Dropbox's "How to set a file or folder to be ignored" page. Which attribute applies depends on how your Dropbox is set up.
One caution before you run it. An ignored folder stays on your local disk, but it is removed from Dropbox's servers and from your other devices. That is fine for build, which you can regenerate. Do the same to a folder you would miss and it disappears from your other machines. Keep it to generated output.
Then delete the copies.
# Look at the list first
find . \( -name "*conflicted copy*" -o -name "*競合コピー*" \) -print
# If it looks right, run it again with -delete
find . \( -name "*conflicted copy*" -o -name "*競合コピー*" \) -deleteI split it into -print and then -delete so a pattern that is too broad can't take a real file with it.
Finally I ran ./gradlew clean and rebuilt. The build went through, and the same morning hasn't come back.
Audit the other generated folders the same way
build and .gradle were not special. Any folder whose contents get swapped out on every build or package install has the same nature. For a web project that might be node_modules or .next; on iOS, DerivedData.
When I open a project now, I ask of each folder: can I delete this and recreate it with one command? If yes, there is no reason to sync it, and syncing it only plants seeds for conflicted copies. If no, and it sits outside sync, a dead disk takes it with it. Writing the answer per folder in a short note makes the decision take almost no time later.
Before you let an agent run builds, decide where the project lives
This part is the line I drew after the failure.
When you hand work to a coding agent such as Gemini CLI, builds and tests run far more often than when you do it by hand. A sync client chasing files that get rewritten every time raises the number of chances for this to happen. I have not tested this with an agent myself. It is reasoning from how the pieces work, but having seen a pile of conflicted copies once, it is the kind of risk I would rather handle in advance.
For how to use the agent itself, see the Gemini CLI guide and the CLI error troubleshooting guide. Here I only settle where files live.
My two rules:
- Sync source and settings. Never sync build output
- If I build inside a synced folder, I mark the output folders as ignored before the first build
Sync what I'd miss, keep out of sync what I can rebuild. On the nights before a deadline, when I'm in a hurry, this is the sentence I go back to.
What to do next
Run just the one-line count in the project you're using right now. If it says 0, carry on. If it finds even one, start by taking build out of sync. That is where I started.