When an Xcode build on a remote cloud Mac suddenly reports Cycle inside ... or Multiple commands produce ..., the easiest mistake is to delete DerivedData immediately. That may temporarily change the order of the errors, but it also erases useful diagnostic evidence. A more reliable approach is to hold the code, Scheme, configuration, and Xcode path constant, preserve the complete log, and then determine whether the problem is a Target dependency cycle or multiple Build Phases competing for the same output path.
Capture a stable reproduction first
Before troubleshooting, pause automatic code pulls, dependency upgrades, and concurrent builds so the workspace does not change between experiments. Record the current commit, the Xcode version, and the developer directory that is actually selected:
set -o pipefail
git rev-parse HEAD
xcodebuild -version
xcode-select -p
mkdir -p .diagnostics
xcodebuild \
-project App.xcodeproj \
-scheme App \
-configuration Debug \
-destination 'generic/platform=iOS Simulator' \
-showBuildTimingSummary \
build 2>&1 | tee .diagnostics/build.log
If the project uses a Workspace, replace -project App.xcodeproj with -workspace App.xcworkspace. Do not pass both options. Next, extract the relevant locations while retaining the original log for context:
grep -nE \
'Cycle inside|cycle in dependencies|Multiple commands produce|will be run during every build' \
.diagnostics/build.log
The final command shown in the log is usually where the conflict was detected, not necessarily where the cycle began. Follow the dependency chain reported by Xcode upward until you find the first repeated Target, script, or output path.
Distinguish between two similar-looking errors
A dependency cycle means A must wait for B while B, directly or indirectly, must wait for A. A duplicate output means two commands both claim responsibility for the same file. The two errors can occur together, but they require different fixes.
| Log symptom | Check first | Common root cause |
|---|---|---|
Cycle inside |
Target Dependencies, implicit dependencies | App and Framework depend on each other |
Multiple commands produce |
Copy Files, Compile Sources, Run Script | The same file is copied or generated twice |
| Script runs on every build | Run Script inputs and outputs | Dependencies are undeclared, or dependency analysis is disabled |
| Failure occurs only during Archive | Embed phase, archive scripts | Debug and Release phases are configured differently |
Use commands to confirm the Targets and configuration actually used for this build rather than guessing from the options currently displayed in the Xcode interface:
xcodebuild -list -json -project App.xcodeproj \
> .diagnostics/project-list.json
xcodebuild -showBuildSettings \
-project App.xcodeproj \
-scheme App \
-configuration Debug \
> .diagnostics/build-settings.txt
Trace the dependency chain through Targets and Build Phases
In Xcode, begin under Target Dependencies with the Targets at the start and end of the reported chain. An App can depend on a Framework, but the Framework should not depend on the App merely to access types defined there. Move shared code into a separate module, or remove the reverse reference by using protocols and dependency injection.
Then inspect each Build Phase in turn, paying particular attention to the following relationships:
Check for duplicate ownership
The same source file should not appear in two Compile Sources entries that generate the same object file. Likewise, a Framework should not be handled both by an automatically generated embed phase and copied again by a custom Copy Files phase. For code generators, define a specific output directory and avoid writing generated output back into a source directory that another Target already compiles.
Check implicit dependencies
If a script reads another Target's build product from a fixed path without declaring an explicit dependency, the build order may change with the level of parallelism. Do not hide the problem by disabling parallel builds. That only makes the error harder to trigger; it does not repair the graph.
Declare Run Script inputs and outputs explicitly
Run Script phases are a common source of cycles. When a script reads configuration files, generates Swift files, or copies resources, specify its Input Files and Output Files in the phase, or use file lists. The script must also ensure that each output is owned by exactly one phase.
For example, a script that generates a version file can first validate the required variables, then use a temporary file and an atomic replacement:
set -euo pipefail
input="${SRCROOT}/Config/version.txt"
output="${DERIVED_FILE_DIR}/GeneratedVersion.swift"
tmp="${output}.tmp"
test -f "$input"
mkdir -p "$(dirname "$output")"
version="$(tr -d '
' < "$input")"
printf 'enum GeneratedVersion { static let value = "%s" }
' \
"$version" > "$tmp"
if test -f "$output" && cmp -s "$tmp" "$output"; then
rm "$tmp"
else
mv "$tmp" "$output"
fi
The corresponding phase should declare $(SRCROOT)/Config/version.txt as an input and $(DERIVED_FILE_DIR)/GeneratedVersion.swift as an output. Placing generated files in the derived directory makes ownership easier to establish than modifying repository files directly, and it reduces the risk of concurrent tasks overwriting one another.
Validate the fix with minimal changes
Change only one dependency, one phase, or one output path at a time, then save a new log. Removing several references at once may make the build pass, but it becomes difficult to confirm the actual root cause and may leave the same issue unresolved in the archive configuration.
Validate the fix in this order:
- Run one clean build and confirm that the complete graph can be constructed from scratch.
- Without cleaning, run two consecutive builds and confirm that scripts correctly skip unchanged inputs.
- Check Debug and Release separately. For a release project, also run Archive once.
- Compare the two logs and confirm that no new duplicate outputs or unconditional script warnings appear.
- Document changes to Target dependencies, phase inputs and outputs, and the reason for each change in the code review description.
Deleting DerivedData can be used as a final isolation experiment, but it is not a fix. A genuinely stable Xcode project should produce the same dependency order across different levels of parallelism and during both clean and incremental builds. Only then will interactive development on a cloud Mac and unattended jobs avoid random failures caused by scheduling changes.
Frequently asked questions
Does deleting DerivedData fix an Xcode build cycle?
Usually not. It removes stale intermediate files, but a cycle caused by target dependencies or duplicate output paths will return during the next build.
Why do Run Script phases often cause build graph problems?
If a script omits declared inputs and outputs or writes to a path owned by another phase, Xcode cannot establish a reliable execution order.
How should the fix be validated?
Run one clean build followed by two builds without cleaning, then confirm that cycle errors, duplicate outputs, and unconditional script warnings are all gone.
Run your next Remote Mac task on a dedicated physical node
Choose from two available configurations, five nodes, and daily, weekly, monthly, or quarterly terms. Review the full configuration and USD amount before ordering.