Help me understanding troubleshooting steps for SPM

Hi Team,

Could you give me some tips on how to troubleshoot issues with SPM? Where can I find logs? How can I know what's triggering Xcode to run Package Resolve? Are there any ways to learn if there are cyclic dependencies? I'm not looking for somebody to do the work for me, just some tips or existing documentation that you can point me to, so that I can start my own research.

I'm currently working on a medium size application with a team of 15 developers to give you the understanding of the scale. The application is approximately 7-8 years old and has a mixture of Objective-C, C++ and Swift code. Most of it is written in Swift. The application used to use Carthage for dependency management, but we've made a big push to move a lot of dependencies to SPM and now a lot of our developers regretting the switch. Here are some of the things that seem to be bothering lots of developers:

It looks like whenever we change branches, Xcode kicks off "Resolve Package" process even though nothing has changed in dependencies nor in Package.resolved file. This process at times completes within seconds, at times within minutes, and sometimes can take up to 45 minutes completely blocking us from doing any work.

Sometimes Xcode throws random SPM errors like SwiftPM.SPMRepositoryError error 5. At times restarting Xcode is enough to fix this problem, other times we are forced to reset package caches and then resolve the packages again.

Sometimes Xcode cannot find local packages. Usually restarting Xcode is enough to fix this problem.

Any help is greatly appreciated.

2 Likes

Xcode isn’t as good at surfacing errors or providing readable description for them, so unless the cause is immediately obvious, I switch to command line SwiftPM ($ swift package) until the problem is solved. (It even has a --verbose flag, although I have never needed it.) Then I go back to Xcode and usually it works immediately. But in some cases Xcode is still tied in a knot from before, and then resetting the package caches and derived data cures it.

Unfortunately this does not work if the project is an application and not itself a package. This has not mattered much for me, because I have long been sinking everything except @main extension MyApplication {} and the bundle bits like Info.plist into a package anyway. Since the application only has one direct dependency, if the package resolves, then so does the application.

I surmise that it does so when it detects that Package.swift or Package.resolved changed in the file system (which implies a likely change in what dependencies are needed), or when a file is added or removed (forcing it to reload the manifest since parts of it are dependent on the file system context; this cannot have changed the dependency list, but reloading the manifest would involve resolution as a side effect, albeit usually just verifying that the pins are valid and checked out).

Command line SwiftPM detects and reports this clearly (unless you have found a new way to trick it).

If the .resolved file is valid and unchanged, it should be near instantaneous for it to recognize that it already has everything it needs.

When this has not been the case, it has generally been caused by a particular class of bugs, where the logic differs slightly between the validation and resolution. Basically it looks invalid at first glance, but then successfully resolves back to the same thing, and then trusting its resolution, it does not bother validating. Then inevitably the process repeats every time you touch it. There have been a handful of separate issues over time, but all of them revolve around URLs differing in minute ways between manifests. One package depends on Such‐and‐Such while another depends on such‐and‐such.git; the resolver considers them equal but the validator thinks they are different. I do not know which particular bugs have been fixed and which remain, or if any have reappeared. Differences in letter case, file extension and URL protocol have been triggers at one point, as has inconsistent use of aliases, symlinks and redirects. If a package is re‐resolving all the time for seemingly no reason, the first thing I do is audit it and its dependencies for variants. So far I have never met a package this does not fix. You can find how far down the dependency tree the problem is by trying each package downwards until the problem goes away. If you can pinpoint such an issue, please report it as a bug.

When switching branches I always (try to remember to) close the project. After switching branches in the terminal and re-opening the project it will resolve normally, which in many cases will be brief.

Our team has been experiencing error 5 for the past year with Xcode 13. It happens randomly, and clearing all caches and derived data helps, but sometimes you need to do it multiple times, and if you have a lot of dependencies (30-50), it takes a really long time.

With Xcode 14, we are now getting error project: Error while fetching remote repositorygit@github.com:***/***.git: An unknown error occurred. reference 'refs/remotes/origin/master' not found. I suspect this is the same error as error 5 from Xcode 13, just with more details now.

Swift Package Manager has been really great for our team, but this single issue has been a source of a lot of frustrations. We were hoping it would be resolved with Xcode 14, but seems like we just got a better error message.

1 Like

Here is a small script I made to work around this problem. It's not ideal, but it's better than deleting all caches: ios - SPM unknown error reference not found when changing branch - Stack Overflow.

1 Like

For me I was encountering similar to the error that you pointed out in Xcode 14

For me pulling changes is when I faced issues:

Error while fetching remote repository/.....: An unknown error occurred. reference 'refs/remotes/origin/main' not found (-1)

exhausted attempts to resolve the dependencies graph, with '<package name> remoteSourceControl git@github.com:.....git' unresolved.

Workaround:

Switching from SSH to using HTTPS URL for the swift package URL in the app's swift package dependancy fixed the issue for me.