Hive Hive
Sign in

SwifterPM restores a static-SPM XCFramework without its binary — deterministic ARCHIVE FAILED (AppsFlyerLib 6.17.0)

GitHub issue · Open

Metadata
Source
tuist/tuist #12367
Updated
Aug 15, 2026
Domains
Generated projects
Details

Summary

With tuist 4.204.0 (SwifterPM enabled by default) and an up-to-date committed Package.resolved, tuist install completes fast and reports success — but the restored AppsFlyerLib.xcframework (a static xcframework shipped as a GitHub release asset) is missing the binary inside the framework slice. The subsequent archive fails with Build input file cannot be found: …/AppsFlyerLib.framework/AppsFlyerLib. Reproduced 2/2 on identical re-runs (deterministic, not a race). The same project builds fine when the artifacts come from classic SwiftPM, so the zip itself is good — the SwifterPM restore/extraction loses the binary.

Environment

  • Runner: GitHub-hosted macos-26-xlarge (5 vCPU, virtualized M2 Pro), macOS 26 image, Xcode 26.6.
  • tuist: 4.204.0 via mise (aqua backend). SwifterPM active (default; logs show its downloading <package>.<target> phrasing and --cache-path ~/.cache/swifterpm).
  • Package.resolved committed at the repo root and up to date (regenerated with 4.204.0 immediately before).
  • Cold state: fresh VM, empty ~/.cache/swifterpm, empty .build.
  • Project: large modular iOS app, ~45 SPM dependencies, 18 binaryTargets.

How it was run

  1. tuist install — SwifterPM restores 45 source packages and downloads all 18 binary targets (downloading appsflyerframework.AppsFlyerLib, downloading grpc-binary.grpc, …). Finishes in ~2 minutes and reports ✔ Success.
  2. tuist generate, then xcodebuild archive (via fastlane gym) for a device build.

How it failed

error: Build input file cannot be found:
'/Users/runner/Library/Developer/Xcode/DerivedData/<app>-…/Build/Intermediates.noindex/
ArchiveIntermediates/<scheme>/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/
AppsFlyerLib.framework/AppsFlyerLib'.
Did you forget to declare this file as an output of a script phase or custom build rule
which produces it? (in target '<analytics target>' from project '<project>')
** ARCHIVE FAILED **

The missing file is the framework’s executable itself: the restored xcframework directory exists, but the AppsFlyerLib binary inside the ios-arm64 slice does not (or is not where the build expects it).

The artifact

https://github.com/AppsFlyerSDK/AppsFlyerFramework/releases/download/6.17.0/AppsFlyerLib-Static-SPM.xcframework.zip — note it is a static xcframework distributed as a GitHub release asset; the other 17 binary targets in the graph (mostly dynamic xcframeworks from dl.google.com) did not produce this error.

Determinism

Re-running the identical workflow (same commit, same cold VM class) failed at the same file, 2/2. This does not look like the concurrent-restore race from #12228 — it reproduces every time with the same artifact.

Possibly related

  • #11444 (fix(cli): restore GitHub release asset binary artifacts) — same artifact class.
  • #12228 (pins dedupe skipped with committed Package.resolved).

Happy to provide full CI logs. Workaround on our side for now: staying on 4.182.0 with pre-seeded classic-SwiftPM caches.

Related: the hang that pushed us to try SwifterPM in the first place is reported in #12366.

Flights

Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.

New Flights are paused Configure model inference, GitHub, and a sandbox provider to start another Flight. Existing results remain available below.
No Flights yet

Start a Flight and preserve its objective, outcome, and session here.

Comments
D
dosubot[bot] Aug 15, 2026

Hi @danieldalto! I’m Dosu and I’m helping the Tuist team.

The ARCHIVE FAILED / “Build input file cannot be found” error you’re seeing on AppsFlyerLib.framework/AppsFlyerLib matches a defect in how Tuist generated the -Wl,-force_load linker flag for static xcframeworks — rather than an issue with SwifterPM’s zip extraction.

Root cause: TARGET_BUILD_DIR vs BUILT_PRODUCTS_DIR

PR #10953 introduced automatic -force_load for static xcframeworks linked by dynamic targets, pointing the flag at $(TARGET_BUILD_DIR). During an archive build (ACTION=install with SKIP_INSTALL=YES), these two directories diverge [1]:

Setting During archive
BUILT_PRODUCTS_DIR ArchiveIntermediates/<scheme>/BuildProductsPath/<Config>-<sdk>
TARGET_BUILD_DIR ArchiveIntermediates/<scheme>/IntermediateBuildFilesPath/UninstalledProducts/<sdk>

Xcode’s ProcessXCFramework extracts the slice into BUILT_PRODUCTS_DIR, but the flag pointed at TARGET_BUILD_DIR — a path nothing writes to. Xcode treats that path as a build input node, so the missing file aborts the archive with exactly the error you saw. This was masked on simulator builds (where the two dirs are identical) and only surfaced on device archives [1].

Fix

PR #12202 (merged 2026-08-12) removes the automatic -force_load behavior from StaticXCFrameworkModuleMapGraphMapper entirely, since the automatic force-loading was demonstrated to be unsafe for arbitrary vendor static xcframeworks (duplicate symbols, duplicated ObjC metadata, undefined references from previously unselected archive members) [2].

What to do

  • Upgrade past 4.204.0 to a version that includes PR #12202. Check your changelog or tuist --version to confirm.
  • If you explicitly need force-load behavior for AppsFlyerLib, you can opt in per-target via PackageSettings.targetSettings [2]:
    PackageSettings(
    targetSettings: [
    "AppsFlyerLib": [
    "OTHER_LDFLAGS": .string("$(inherited) -Wl,-force_load,$(BUILT_PRODUCTS_DIR)/AppsFlyerLib.framework/AppsFlyerLib")
    ]
    ]
    )

The symptoms you describe (xcframework directory exists, binary inside the slice absent) more precisely match the stale TARGET_BUILD_DIR linker path than an incomplete download/extraction. If upgrading doesn’t resolve it, posting the full CI logs — particularly a find ~/.cache/swifterpm -name "AppsFlyerLib" -type f after tuist install — would help confirm which layer is at fault.

To reply, just mention @dosu.


Share context across your team and agents. Try Dosu.

Leave Feedback Learn about tuist with Dosu Add Dosu to your team