Hive Hive
Sign in

SwifterPM: Fails to strip first level directories of registry packages

GitHub issue · Open

Metadata
Source
tuist/tuist #11463
Updated
Jun 23, 2026
Domains
CLI
Details

What happened?

Was doing some testing of our private repo (which utilizes package registries) against 4.201.0 RC.1 and SwifterPM enabled. Error occurs on a fresh clean of all SPM caches and complains of invalid source file globs. This is caused by the resulting .build folder having an invalid file path for the source file globs due to a directory not being stripped.

Problematic registry .zip structure at the root (which gets copied into Tuist/.build/registry/.../REPO_NAME/VERSION/)

  • Package.swift
  • discarded
    • Sources

SPM relevant code: stripFirstLevel Notably uses a filter checking if the top level items are directories

SwifterPM relevant code: flattenSingleDirectory Simply checks count of contents in the top level directory

How do we reproduce it?

In theory could probably write a test to exercise this code path in SPM vs SwifterPM. Unfortunately can’t setup a sample project since this registry package is private, but hopefully the above description can provide enough context to reproduce & fix.

Error log

The target PACKAGE_NAME has the following invalid source files globs:
- The directory "FILE_PATH" does not exist.

macOS version

26.5.1

Tuist version

4.201.0-rc.1

Xcode version

26.5

Comments
D
dosubot[bot] Jun 23, 2026

Good catch. I can confirm the issue you’ve identified. The root cause is in flattenSingleDirectory — it counts all top-level entries (files and directories) via contentsOfDirectory, then bails out if the count isn’t exactly 1:

let entries = try await contentsOfDirectory(url.absolutePath)
guard entries.count == 1 else { return }

SPM’s stripFirstLevel, by contrast, filters to only consider directories at the top level before deciding whether to flatten. So in your case with:

- Package.swift (file)
- discarded/ (directory)
- Sources/

SPM sees one directory (discarded/) and flattens it, while SwifterPM sees two entries (Package.swift + discarded/) and skips flattening entirely — leaving the source paths broken.

Interestingly, SwifterPM already has a shouldStripFirstLevel function for binary artifacts that correctly counts only subdirectories [1], but this logic isn’t applied to registry source package extraction [2].

The fix would be to filter entries to only directories (and non-symlinks) before checking the count, matching SPM’s behavior.

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