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.

Missing package product 'PerceptionCore'
Missing package product 'Collections'
Missing package product 'Perception'
Missing package product 'SwiftUIIntrospect'

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:

  1. A resolved dependency entry in Package.resolved
  2. Fetched source code in ~/Library/Developer/Xcode/DerivedData/.../SourcePackages/checkouts/
  3. A compiled framework or static library produced by the package
  4. 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

Solution 1

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 PerceptionPerceptionCore got extracted into a separate product). Xcode just needs to refetch.

File → Packages → Update to Latest Package Versions
Solution 2

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.

File → Packages → Reset Package Caches
Solution 3

Delete Derived Data

5–15 minutes · build cache wipe

If 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.

# Quit Xcode first rm -rf ~/Library/Developer/Xcode/DerivedData
Solution 4

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.

# From your project root rm -f <YourProject>.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved # Or for workspaces: rm -f <YourProject>.xcworkspace/xcshareddata/swiftpm/Package.resolved

Then File → Packages → Resolve Package Versions to regenerate. Diff the new file against the old one before committing — versions may have shifted.

Solution 5

Quit Xcode Completely (Yes, Really)

30 seconds · memory cache flush

Sometimes 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.

killall Xcode killall com.apple.dt.Xcode.sourcekitd
Solution 6

Check Your Xcode Version

if all else fails · toolchain check

Some 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.

xcodebuild -version // Cross-reference with the package's Package.swift: // swift-tools-version: 5.10 ← requires Xcode 15.3+
Solution 7

Check for Conflicting Dependency Managers

CocoaPods + SPM projects only

If 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.

# In project root pod deintegrate pod install # Then in Xcode: Reset Package Caches → Clean Build Folder → Build
Solution 8

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.

# 1. Quit Xcode killall Xcode # 2. Clear all caches rm -rf ~/Library/Developer/Xcode/DerivedData rm -rf ~/Library/Caches/org.swift.swiftpm rm -rf ~/Library/Caches/com.apple.dt.Xcode # 3. Remove resolved file rm -f <YourProject>.xcworkspace/xcshareddata/swiftpm/Package.resolved # 4. Reopen Xcode open <YourProject>.xcworkspace

In Xcode: File → Packages → Resolve Package Versions, wait for full resolution, then build.

Full walkthrough on Medium · 7 min read

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.resolved was resolved by picking "ours" or "theirs" instead of re-running resolution.
  • Xcode was updated but DerivedData survived 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.

TriggerStart With
Package was just updatedSolution 1 — Update to Latest
Switched branchesSolution 2 — Reset Package Caches
Package.resolved merge conflictSolution 4 — Delete Package.resolved
Xcode was updatedSolution 3 — Delete DerivedData
Multiple Xcode versions on machineSolution 8 — Nuclear
No obvious triggerSolution 5 (Quit Xcode) → Solution 3
Project uses CocoaPods + SPMSolution 7 — Conflicting managers
Older Xcode + new packageSolution 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.

  1. 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.
  2. Tip 02Run Reset Package Caches after 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.
  3. Tip 03Don't resolve Package.resolved merge conflicts manually. Delete the file, re-resolve, commit the regenerated version. Manual resolution is a near-guaranteed way to ship a poisoned file.
  4. 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.
  5. Tip 05Pin major versions in Package.swift. Use .upToNextMajor(from: "1.0.0") instead of .upToNextMinor or 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: