Runs interfere through shared on-disk state. You see stale builds, an
.xcresult that belongs to a different run, missing or clobbered logs, or
results that do not match the code you just changed.
What it usually looks like
Two runs writing to the same DerivedData step on each other; one fails to
build or picks up stale products.
A shared -resultBundlePath gets overwritten, so the bundle you open is
from the wrong run.
Coverage or logs are missing/partial because another run truncated them.
“It passed locally” but the artifact you inspect tells a different story.
Symptoms get worse the more runs happen in parallel on one Mac.
Why it happens / likely failure classes
The default paths are shared and global, which is fine for one run at a time
and fragile otherwise:
Default DerivedData (~/Library/Developer/Xcode/DerivedData) is shared
across invocations unless you override it. Concurrent builds collide there.
Fixed result-bundle / log paths mean a second run overwrites the first.
Incremental build state carried between unrelated runs produces stale
products.
This is an artifact/state problem, not a test-correctness problem — the
tests themselves may be fine.
Quick checks
# Are multiple runs sharing the default DerivedData right now?ls -la ~/Library/Developer/Xcode/DerivedDatapgrep -lf xcodebuild# Confirm each run can take its own DerivedData + result bundlexcodebuild test -scheme YourScheme \ -destination "platform=iOS Simulator,id=<UDID>" \ -derivedDataPath "/tmp/dd-$RUN_ID" \ -resultBundlePath "/tmp/result-$RUN_ID.xcresult"
Manual mitigations
Give every run its own DerivedData and artifact paths:
Never point two concurrent runs at the same output paths.
Clean up per-run directories afterward so disk does not fill.
If you must share DerivedData, serialize the runs so only one writes at a
time.
When XCSteward may help
Per-run isolation of artifacts is one of XCSteward’s core design goals:
Isolated DerivedData, logs, .xcresult, and JSON summaries per job, so
runs cannot overwrite or read each other’s state.
A single execution lane / queue so concurrent runs do not contend for
shared build state in the first place.
Deterministic cleanup of per-run directories after a job completes.
Inspectable job evidence through status, logs, artifacts, and
explain --json, so a human or agent can identify the exact run and artifact
paths before drawing conclusions from stale output.
Ownership metadata through repeatable submit --metadata key=value and
--label, which can make agent-created artifact sets easier to attribute.
A strong candidate to test against this class of failure, particularly when
several runs share one Mac.
When XCSteward probably will not help
If your tests share external state (a backend, a database, fixtures on
disk outside DerivedData) that collides across runs, that is your
responsibility to isolate.
It does not fix incorrect build settings that produce stale products on
their own.
It is not a build-cache product; it isolates and cleans up paths, it does not
speed up compilation.
Common questions
What does "DerivedData contamination between iOS test runs" usually mean?
It usually points to shared artifacts / DerivedData contamination. Test runs interfere through shared DerivedData, result bundles, or logs — you get stale builds, overwritten .xcresult, or results from the wrong run. Start by checking simulator readiness, destination selection, CoreSimulator/simctl responsiveness, and whether another xcodebuild, simctl, or Simulator process is already active before treating it as a test-code failure.
Can XCSteward help with "DerivedData contamination between iOS test runs"?
This is a strong fit when the failure is operational: simulator readiness, destination resolution, CoreSimulator responsiveness, cleanup, timeouts, or local concurrency. XCSteward may help by making those phases bounded, serialized, and easier to inspect. It will not fix broken tests, code signing, missing runtimes, or vendor image bugs.
What should I check first?
Check whether xcrun simctl commands return promptly, whether xcodebuild can resolve a concrete simulator destination, whether the device is truly ready rather than merely Booted, and whether concurrent agents, scripts, or manual runs are touching the same simulator subsystem.
Simulator fails after a previous test run — The first run is fine, but the next test run on the same simulator fails or hangs — state from the previous run leaked into this one.
fastlane scan hangs after tests finish — All tests pass, but fastlane scan never exits — it hangs after the last test during teardown, result-bundle writing, or simulator shutdown.