DevOps / CI·CD May 20, 2026

2026-05-20 Xcode 16 provisioning profile paths and multi-lane concurrent archive on a headless leased Apple Silicon cloud Mac (HK / JP / KR / SG / US)

MacXCode Engineering Team May 20, 2026 ~18 min read

Teams that lease Mac mini M4 builders in Hong Kong, Tokyo, Seoul, Singapore, or the United States and run Xcode 16 headlessly hit a quiet breaking change: provisioning profiles no longer “live” only under the legacy MobileDevice tree. Xcode 16 reads and writes the canonical store under UserData, while older scripts, Fastlane helpers, and third-party CLIs may still copy .mobileprovision files to the pre‑Xcode path. When you add multi-lane concurrent xcodebuild archive on one leased host, that path drift becomes signing races, phantom “profile not found” errors, and intermittent errSecInternalComponent failures that never reproduce on a developer laptop. This 2026-05-20 runbook states the policy up front: mirror profiles into both UserData and legacy locations until every tool on the host is Xcode‑16 aware, isolate per-lane CI keychains and DerivedData roots, and cap concurrent Archive lanes to two on a stock Mac mini M4 unless you have measured NVMe and unified-memory headroom. You will get a path comparison table, a multi-lane matrix, headless signing triage, an eight-step rollout, and FAQ answers aligned with our keychain + provisioning CI baseline, automatic vs manual signing guide, and parallel xcodebuild discipline article.

Who hits provisioning path drift on a leased headless Mac

The failure rarely announces itself as “wrong directory.” Instead, lane B’s Archive succeeds while lane A reports No profile for team 'XXXXXXXXXX' matching even though both jobs imported the same UUID. On a leased host the blast radius is larger: golden images bake in helper scripts from 2024, Jenkins plugins still call ~/Library/MobileDevice/Provisioning Profiles, and a new hire’s Fastlane lane downloads into UserData while overnight cron only refreshes the legacy folder. Multi-branch CI that shares one macOS user account amplifies the drift because every lane reads the same home directory unless you deliberately partition paths.

  • Release engineers running two or more concurrent Archives for different bundle IDs on one Mac mini M4 need deterministic profile resolution per lane.
  • Platform teams maintaining golden images must document which path Xcode 16, xcodebuild, and auxiliary tools read during archive and exportArchive.
  • Security reviewers want proof that lane A cannot read lane B’s distribution certificate—per-lane keychains are non-negotiable when profiles are hot-swapped.

Start every design review from the MacXCode home promise: Apple Silicon close to Apple APIs, then map which signing artifacts must co-locate with the checkout on the lease host. If you are still copying profiles only to MobileDevice, treat that as technical debt blocking reliable multi-lane throughput—our remote Archive guide predates the UserData shift and must be read together with this update.

Legacy MobileDevice vs Xcode 16 UserData profile paths

Xcode 16 treats ~/Library/Developer/Xcode/UserData/Provisioning Profiles as the primary on-disk store when you download profiles from Xcode’s Accounts pane or when xcodebuild -allowProvisioningUpdates refreshes entitlements. The legacy location ~/Library/MobileDevice/Provisioning Profiles remains relevant because many CI recipes, older Fastlane actions, and internal shell installers still target it exclusively. Until you audit every entry point, the safe operator default is byte-identical copies in both trees after each profile rotation, using the UUID filename Apple embeds in the plist (security cms -D -i file.mobileprovisionUUID key).

Path Typical consumer Xcode 16 behavior CI note on leases
~/Library/Developer/Xcode/UserData/Provisioning Profiles Xcode IDE, modern xcodebuild Canonical read/write for GUI downloads Pin xcode-select before copying; verify with Accounts export
~/Library/MobileDevice/Provisioning Profiles Legacy scripts, some Fastlane versions Still honored by many CLI flows Mirror here until scripts are retired
Lane-scoped staging (e.g. /var/ci/lane-a/profiles) Custom installers before copy Not read directly; reduces home-dir races Copy into both canonical paths per lane job
ASC API + -allowProvisioningUpdates Automatic signing pipelines May populate UserData only Seal API keys; see Fastlane vs native ASC
Numeric guardrail: keep 7–14 days of overlapping profile validity when rotating distribution profiles; lanes that start mid-rotation should never delete the previous UUID until all in-flight Archives finish. Log the three newest profile mtimes beside security find-identity -v -p codesigning as described in the keychain baseline.

Multi-lane concurrent archive matrix on one Mac mini M4

Concurrent Archives are not “free parallelism” on a leased Mac mini M4: unified memory, NVMe queue depth, and signing session state still serialize under load. The matrix below assumes each lane uses a dedicated -derivedDataPath, a dedicated CI keychain, and mirrored profiles—patterns from our parallel jobs guide and scheme + xcconfig multi-branch article.

Lane count Typical NVMe headroom Unified memory Operator verdict
1 serial Archive 120 GB+ free on system volume 16 GB minimum; 24 GB comfortable Default for shared Release trains; simplest logs
2 concurrent Archives 120–180 GB free per lane under /var/ci 24 GB+ recommended Practical ceiling on stock M4; isolate DerivedData + keychains
3+ concurrent Archives 2 TB NVMe class; aggressive cleanup 32 GB+ or expect compression stalls Only after measured metrics; schedule disk hygiene
Archive + heavy test shard Separate roots; never share ModuleCache Leave 4 GB headroom for XCTest Prefer serial Archive after tests or separate hosts

Example lane-scoped archive invocation (manual signing with explicit specifier):

KEYCHAIN_PATH=/var/ci/lane-a/ci.keychain-db DERIVED=/var/ci/lane-a/dd xcodebuild -workspace App.xcworkspace -scheme Release -configuration Release -archivePath /var/ci/lane-a/out/App.xcarchive -derivedDataPath "$DERIVED" CODE_SIGN_STYLE=Manual PROVISIONING_PROFILE_SPECIFIER='MyApp AppStore' archive

Headless signing triage when profiles look “installed”

SSH sessions feel interactive; launchd and CI runners are not. The most common headless failures after an Xcode 16 upgrade are: profiles copied only to MobileDevice, distribution identities imported into the login keychain while xcodebuild points at an empty CI keychain, and lane B unlocking a keychain lane A still needs exclusively. Treat every Archive as a three-part fingerprint: security list-keychains, security find-identity -v -p codesigning, and an ls -lt of both profile directories limited to the newest three UUIDs.

When codesign prints errSecInternalComponent, unlock the CI keychain non-interactively before archive, set partition lists for codesign access, and confirm the provisioning profile’s entitlements match the target’s capabilities—especially Push, App Groups, and Associated Domains after portal edits. Automatic signing with ASC API can mask path drift until export; manual lanes expose it immediately. Read automatic vs manual signing before mixing styles across lanes on one host.

Never run two lanes against the same login keychain on a shared lease. Create ci-lane-a.keychain-db and ci-lane-b.keychain-db under /var/ci, import distribution .p12 files with security import -k "$KEYCHAIN_PATH" -P "$P12_PASS" -T /usr/bin/codesign, and scope security list-keychains -s for each job duration.
Symptom Likely cause Next command or fix
Profile missing in Xcode report UserData empty; legacy-only install Mirror UUID file into UserData; re-run archive
errSecInternalComponent Locked keychain or wrong partition list security unlock-keychain -p "$PASS" "$KEYCHAIN_PATH"; set-key-partition-list
Lane A passes, lane B fails same commit Shared DerivedData or profile race Separate -derivedDataPath; serialize profile copy
Export succeeds, upload rejects Wrong profile type or expired entitlements Validate with export + ASC upload checklist

After Archive, upload dSYMs before you delete lane folders—our dSYM symbolication guide assumes archives remain addressable per lane under /var/ci/…/out.

Eight-step rollout for Xcode 16 paths + multi-lane archive

  1. Pin xcode-select -p to the intended Xcode 16.app; record xcodebuild -version in the golden image manifest.
  2. Audit every script that copies .mobileprovision files; update installers to write both UserData and MobileDevice paths using UUID filenames.
  3. Create per-lane CI keychains and import distribution certificates; deny lanes access to each other’s keychain files.
  4. Export KEYCHAIN_PATH, PROVISIONING_PROFILE_SPECIFIER (or profile UUID), and lane-scoped DERIVED_DATA_ROOT in CI env blocks.
  5. Run a dry xcodebuild -showBuildSettings per lane; confirm CODE_SIGN_STYLE matches policy from signing mode guide.
  6. Enable -allowProvisioningUpdates only when ASC API credentials are sealed and monitored—see native ASC vs Fastlane.
  7. Start with one Archive lane until profile mirroring is stable; add lane two with separate NVMe roots and log files.
  8. Schedule weekly disk cleanup and rotate profiles with overlap; keep hot-swap copies in lane staging dirs.

Non-interactive profile install pattern (replace paths with your lane staging directory):

UUID=$(security cms -D -i "$PROFILE" | plutil -extract UUID raw -) && cp "$PROFILE" "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles/$UUID.mobileprovision" && cp "$PROFILE" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision"

FAQ

Where does Xcode 16 store provisioning profiles? Primary location is ~/Library/Developer/Xcode/UserData/Provisioning Profiles. Legacy tools may still read ~/Library/MobileDevice/Provisioning Profiles—mirror both on CI hosts until all installers are updated.

How many concurrent archive lanes fit on one Mac mini M4? Two lanes with 120–180 GB NVMe headroom each is a practical default; a third lane needs 2 TB storage, aggressive cleanup, and careful memory budgeting per the matrix above.

Why does codesign fail with errSecInternalComponent over SSH? Usually a locked keychain, missing partition list for the CI keychain, or profiles installed only under the legacy path while Xcode 16 resolves UserData first.

Should lanes share DerivedData to speed up builds? No for Release Archives—ModuleCache and index stores race under parallel Archives. Use per-lane -derivedDataPath and optional shared read-only dependency caches only after a single writer resolves packages.

For navigation hygiene, bookmark the blog index and the help center so on-call engineers can find this runbook without searching chat history.

Why Mac mini M4 leases fit multi-lane Xcode 16 Archives

Apple Silicon M4 delivers enough unified memory bandwidth to compile two medium iOS graphs concurrently when you isolate DerivedData and cap lanes honestly. Native macOS code signing avoids hypervisor keychain quirks that plague emulated Mac environments, which matters when three nightly branches each demand a distribution profile refresh. Leasing removes CapEx for burst release weeks: spin a builder in Tokyo for App Store Connect proximity, Singapore for ASEAN egress, or the United States for US-West API endpoints, then scale down when the train ships. Compare regions on the pricing page, rehearse SSH in the help center, and pair this article with remote Archive workflows when onboarding a new repo to a headless lease.

Lease Apple Silicon where Xcode 16 signing stays predictable

HK / JP / KR / SG / US · headless SSH · multi-lane Archive ready