How to Fix "Missing Package Product" Errors in Xcode — The 8-Solution Troubleshooting Path
You didn't change the dependencies. You pulled the latest branch, hit Run, and Xcode tells you four packages are "missing." Not "out of date." Not "version mismatch." Missing. As if you never added them.
Four red X's, no obvious cause, a build that won't compile. The fix usually takes ten seconds — but finding the right fix can take an hour if you don't know which layer is lying to you.
This article maps the 8-solution troubleshooting ladder I built after hitting this error on four different production projects. The full step-by-step walkthrough lives on Medium — link at the end. Below is the framework and the decision tree.
What "Missing Package Product" Actually Means
A "package product" is a library or executable exposed by a Swift package. When your target depends on SwiftUIIntrospect, Xcode expects four things in sequence:
- A resolved dependency entry in
Package.resolved - Fetched source code in
~/Library/Developer/Xcode/DerivedData/.../SourcePackages/checkouts/ - A compiled framework or static library produced by the package
- A working link between your target and that product
"Missing package product" means step 4 broke — Xcode can't connect your target to the product, even though the package itself may be present on disk. The error is misleadingly named: the product usually exists. The binding is missing. Which step actually broke determines which solution works.
The 8-Solution Ladder (Cheap to Nuclear)
Start at solution 1. Climb the ladder only when the layer below is confirmed clean. Each rung is more expensive — in time, lost cache, or re-download cost.
8
Solutions
10s
Cheapest Fix
60%
Solved by #1
100%
Solved by #8
Update Your Package Dependencies
10 seconds · solves ~60%Your Package.resolved references a version that no longer exists, or internal targets shifted between versions (exactly what happened when Perception → PerceptionCore got extracted into a separate product). Xcode just needs to refetch.
Reset Package Caches
1–5 minutes · disk cache rebuild"Update to Latest" runs successfully but red X's stay? The on-disk cache is corrupted. Xcode is happily reading the cached broken version instead of re-fetching. "Update" only refreshes version numbers; "Reset" actually re-downloads the source. Most developers skip this because they assume "Update" already did it.
Delete Derived Data
5–15 minutes · build cache wipeIf reset caches doesn't fix it, the corruption is one layer deeper — in DerivedData. Stale .swiftmodule files keep old product names alive and confuse the linker. This single step has fixed more "phantom" Swift package errors for me than any other.
Delete and Re-Resolve Package.resolved
careful · may shift dep versions
If the error persists, your Package.resolved is poisoned — usually after a merge conflict was resolved incorrectly, or after switching branches with different dependency graphs.
Then File → Packages → Resolve Package Versions to regenerate. Diff the new file against the old one before committing — versions may have shifted.
Quit Xcode Completely (Yes, Really)
30 seconds · memory cache flushSometimes Xcode holds open file handles on package checkouts even after Reset Caches. The cache reset succeeded but Xcode keeps reading the in-memory representation. Cmd+Q isn't enough if background processes survive.
Check Your Xcode Version
if all else fails · toolchain checkSome packages — particularly Perception and anything depending on Swift Macros — require minimum Xcode versions. PerceptionCore was introduced as a separate product in a Perception release that requires Xcode 15.3+. If your Xcode is too old, no amount of cache resetting will help.
Check for Conflicting Dependency Managers
CocoaPods + SPM projects onlyIf your project uses both CocoaPods and Swift Package Manager, Pods can interfere with SPM resolution — especially when both want to manage the same transitive dependency. Collections (Apple's swift-collections) is a frequent victim because many libraries depend on it.
The Nuclear Option
last resort · expensive but 100%If nothing above works, do everything at once. You'll lose every cached build artifact and re-download every dependency — but this fixes every case I've ever seen.
In Xcode: File → Packages → Resolve Package Versions, wait for full resolution, then build.
Read The Complete Troubleshooting Guide
The Medium version goes deeper on each solution — the exact terminal output to expect, why "Update" alone fails 40% of the time, the order to escalate, and the "phantom" symptoms that look like one thing and are actually another.
Read the Full Article on Medium →Why This Keeps Happening
After hitting this error across four different projects, a pattern emerges. "Missing package product" almost always appears after one of these triggers:
The 5 Triggers (Identify Yours, Pick the Right Fix)
- A package was just updated — especially
Perception → PerceptionCore. Internal product extractions broke half the iOS community for a week. - You switched branches with different dependency graphs in
Package.resolved. - A merge conflict on
Package.resolvedwas resolved by picking "ours" or "theirs" instead of re-running resolution. - Xcode was updated but
DerivedDatasurvived from the old version — stale module maps confuse the linker. - You're working across multiple Xcode versions (e.g., Xcode 15 and Xcode 16 on the same machine, switched via
xcode-select).
Decision Table — Trigger → Fix
Identify which trigger fired, jump straight to the matching solution. Stop guessing.
| Trigger | Start With |
|---|---|
| Package was just updated | Solution 1 — Update to Latest |
| Switched branches | Solution 2 — Reset Package Caches |
Package.resolved merge conflict | Solution 4 — Delete Package.resolved |
| Xcode was updated | Solution 3 — Delete DerivedData |
| Multiple Xcode versions on machine | Solution 8 — Nuclear |
| No obvious trigger | Solution 5 (Quit Xcode) → Solution 3 |
| Project uses CocoaPods + SPM | Solution 7 — Conflicting managers |
| Older Xcode + new package | Solution 6 — Xcode version check |
How to Prevent It Next Time
You can't fully prevent SPM weirdness — it's a young tool and Xcode integration has rough edges. But a few habits dramatically cut how often you hit it.
- Tip 01Always commit
Package.resolved. Treat it like a lockfile. If your teammates have a different resolved version, you'll get inconsistent builds. The whole team should pin to the same resolved snapshot. - Tip 02Run
Reset Package Cachesafter every dependency change. Adding a package, removing one, bumping a version — always reset caches after. "Update to Latest" doesn't always cascade through transitive dependencies. - Tip 03Don't resolve
Package.resolvedmerge conflicts manually. Delete the file, re-resolve, commit the regenerated version. Manual resolution is a near-guaranteed way to ship a poisoned file. - Tip 04Keep your team on the same Xcode version — or at least the same major version. SPM behaviors differ subtly across Xcode releases and "works on my machine" becomes very real.
- Tip 05Pin major versions in
Package.swift. Use.upToNextMajor(from: "1.0.0")instead of.upToNextMinoror branch-based dependencies. Major-version pinning gives you bug fixes without surprise breaking changes.
The Real Takeaway
"Missing package product" is one of those errors that looks catastrophic and is almost always trivial — once you know which layer is broken.
Eight times out of ten, it's a stale cache. The other two times, it's a stale Package.resolved or an Xcode version mismatch.
The skill isn't memorizing the fix. It's learning to recognize which layer is lying to you: the version graph, the on-disk cache, the in-memory cache, the compiled artifacts, or the toolchain itself. Start at the cheapest fix (Update Latest, 10 seconds) and escalate only when each layer is confirmed clean.
More iOS Resources Worth Bookmarking
100DaysSwiftUI-to-Expert
The complete 100-article SwiftUI curriculum — fundamentals to production apps, free on Medium.
Open the List →Mastering Claude Code
20 chapters + 50 hidden tips. Pair Claude Code with your iOS workflow to ship features in half the time.
Gumroad — $19 →Medium Income 2026
The 2026 playbook for monetizing your dev knowledge on Medium. Real receipts, 100+ countries supported.
Gumroad — $19 →Frequently Asked Questions
Why does "Update to Latest" fail so often?
Because "Update" only refreshes version numbers in Package.resolved — it does not re-download source code or rebuild caches. If the issue is corruption further down (DerivedData, .swiftmodule files, in-memory cache), bumping the version number changes nothing. That's why solutions 2 and 3 fix the remaining 40%.
Is this error specific to SwiftUI projects?
No. It happens to any iOS, macOS, watchOS, tvOS, or visionOS target that consumes a Swift package. SwiftUI projects just hit it more often because the SwiftUI ecosystem (SwiftUIIntrospect, swift-composable-architecture, Perception, etc.) ships frequent updates with internal product reorganizations.
Can I automate the "nuclear" reset?
Yes — wrap it in a shell script and add it to your project's Scripts/ folder. Just remember it costs 10–20 minutes of re-downloading and re-indexing every time. Save it for when targeted fixes have failed.
Does this affect CI/CD builds?
Yes — CI builds often hit a milder form because they start from a clean checkout. The common CI symptom is "package resolution succeeded but linker can't find product." The fix is usually xcodebuild -resolvePackageDependencies as a pre-build step.
How do I know if it's a stale cache vs an actual missing dependency?
Check ~/Library/Developer/Xcode/DerivedData/<YourProject>-*/SourcePackages/checkouts/. If the package folder is there, the source exists and you have a binding/cache problem (solutions 1–5). If the folder is empty or missing, you have an actual fetch problem (solutions 4 or 8).
Save this article. You'll hit this error again. We all do.
Read The Full Walkthrough On Medium →
No comments: