Skip to content
Latchkey

SwiftPM stale .build / SourcePackages cache in CI

Caching .build (or DerivedData/SourcePackages) speeds up SPM builds, but a cache restored across a dependency change, toolchain change, or platform change can contain modules that no longer match, producing confusing build or module errors.

What this error means

After restoring an SPM cache, builds fail with module-built-for mismatches, "no such module", or stale resolved pins that do not match the current Package.swift.

swift
error: could not build module 'Networking'
note: the module cache at '.build/.../ModuleCache' was built for a different toolchain

Common causes

The cache key ignores the dependency or toolchain version

A cache keyed only on the OS restores .build/SourcePackages from a different Package.resolved or Swift version, so cached modules are wrong.

A platform or architecture change invalidated artifacts

Switching runner architecture or deployment target while reusing a cache mixes incompatible compiled modules.

How to fix it

Key the cache on the resolved file and toolchain

  1. Include Package.resolved and the Swift/Xcode version in the cache key.
  2. Restore only when both match, so stale artifacts are not reused.
  3. On a mismatch, build fresh instead of reusing.
.github/workflows/ci.yml
- uses: actions/cache@v4
  with:
    path: .build
    key: spm-${{ runner.os }}-${{ hashFiles('Package.resolved') }}

Clear the cache when artifacts are mismatched

When a build shows module-mismatch errors, remove the cached build directory and rebuild.

Terminal
rm -rf .build
swift build

How to prevent it

  • Key SPM caches on Package.resolved plus the Swift/Xcode version.
  • Invalidate the cache on architecture or platform changes.
  • For Xcode, cache the cloned SourcePackages directory with a matching key.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →