darkowlzz

dep - Solve Errors

5 minute read Published:

dep seems to work great for those who are able to get it to work with their projects. But often, there are issues that a new dep user faces while trying out dep for the first time. The issues when dep fails to solve the dependency graph. When this happens, dep needs some help from the user to solve the issue.

A lot of people find it hard to get started with dep when the very first command, dep init fails and they don’t know how to go ahead with that. init scans the project, collect all the project information and perform a solve to obtain a solution of the dependency graph. Once a solution of obtained, it writes out a manifest file(Gopkg.toml) and a lock file(Gopkg.lock). The lock file contains a complete solution of the dependency graph at a given time. The manifest contains flexible constraints based on the solution.

An init solve failure error looks like this:

init failed: unable to solve the dependency graph: Solving failure: No versions of github.com/foo/exampleA met constraints:
    v1.8.1: Could not introduce github.com/foo/exampleA@v1.8.1 due to multiple problematic subpackages:
	Subpackage github.com/foo/exampleA/logger is missing. (Package is required by github.com/bar/exampleB@v23.1.)
    v1.8.0: Could not introduce github.com/foo/exampleA@v1.8.0 due to multiple problematic subpackages:
	Subpackage github.com/foo/exampleA/logger is missing. (Package is required by github.com/bar/exampleB@v23.1.)
    ...

Here, dep is trying to tell what’s the issue that is confusing it and it can’t complete the solve. In a way, it’s asking for some help. It could appear to be scary at the beginning, and the error message could be very cryptic.

A closer look at the errors and the projects could help in better understanding the issue. This example is taken from a real issue that was reported. So, github.com/bar/exampleB at version v23.1 depends on github.com/foo/exampleA by importing github.com/foo/exampleA/logger. But package logger seems to be missing from foo/exampleA project at version v1.8.1.

dep has the nature of prefering semver releases and it looks at the latest semver release of a project and then goes down the releases to find the version that satisfied the requirement. In this case, v1.8.1 is the latest release of project github.com/foo/exampleA. Since bar/exampleB needs something that’s not in foo/exampleA’s latest release, means that maybe bar/exampleB depends on some newer, unreleased version of foo/exampleA or maybe some old version that had the required package. dep would check all the versions, including branches to find a compatible version of foo/exampleA. If it can’t find any, it would fail.

Since dep checks against all the versions and branches, a failure means that the package “logger” doesn’t exist in any of the releases or branches. Maybe it was in some branch at some point in time, but some new commits have removed it. One way to solve this would be to get a newer version of github.com/bar/exampleB that’s compatible with a proper release of github.com/foo/exampleA. Lets say, master branch of github.com/bar/exampleB is in development and seems to be working with the new releases of foo/exampleA. To tell dep to use the master branch of bar/exampleB, create a Gopkg.toml file at the root of your main project and add:

[[constraint]]
  name = "github.com/bar/exampleB"
  branch = "master"

With this, the manifest file is manually created. Running dep init would fail because a manifest already exists. So, run dep ensure and dep would read the manifest and know which version of bar/exampleB to use. If everything remains well, the solve would complete and a lock file would be generated. If not, some more errors similar to previous solve errors would show up and they could be dealt with in the same way, by telling dep which version of the project to use.

The above case is an example of how to troubleshoot when there’s a solve failure. If all the projects maintain proper releases there shouldn’t be such issues. In case of github.com/bar/exampleB, a new release of the project that depends on new version of github.com/foo/exampleA would also solve the issue.

Another type of solve error looks like this:

✗   github.com/foo/exampleA@v0.0.5 not allowed by constraint master
    master from (root)

This means that dep checking if version v0.0.5 of foo/example is compatible with the main project, but the root project (main project) has defined a constraint for foo/example to use “master” branch. This can again be tuned according to the needs in the Gopkg.toml file, and help dep in deciding which version to use.

dep hash-inputs

There’s a hidden tool in dep that can help in debugging the issues when dep behaves in an unexpected way. Let’s say the main project is github.com/foo/projectA. And in the project, there’s say, package “foo”, that imports package “bar” of the same project. The import path would be github.com/foo/projectA/bar. If for some reason, the project in the development machine has the name of the project parent directory as “Foo” instead of “foo”. The project path is github.com/Foo/projectA. Running dep with this setup would confuse dep.

The solve error would contain error lines about unable to find github.com/Foo/projectA. Usually, dep would ignore the main project. But in this case, due to the issue in the directory name, dep would not ignore it and try to find the project and fail.

This wouldn’t be apparent for someone who hasn’t faced this issue. I recommend using dep hash-inputs to see what is dep able to see in the project. These are the inputs that are used by dep to perform a solve and come up with a complete dependency graph.

An example hash-inputs result would be:

$ dep hash-inputs
-CONSTRAINTS-
-IMPORTS/REQS-
github.com/bar/exampleB
github.com/foo/exampleA/common
github.com/foo/exampleA/common/hexutil
github.com/foo/exampleA/common/math
gopkg.in/redis.v3
-IGNORES-
-OVERRIDES-
-ANALYZER-
dep
1

If the main project is seen in the above list, it’s clear that something is wrong with the import paths or the project directory organization. hash-inputs can only be generated when there’s a manifest file. Even an empty Gopkg.toml file is enough to generate hash-inputs results.

More details about the failures in dep could be found at https://golang.github.io/dep/docs/failure-modes.html.

comments powered by Disqus