Clojure How To Find and Manage Dependency conflicts.

Viewed 1071

I recently ran into an issue where including a new dependency in my project broke the functionality of another, unrelated one.

The two in question:

[amazonica "0.3.132"]
[abengoa/clj-stripe "1.0.4"]

Including the above stripe breaks the amazon one, and throws the following error for s3 operations

ERROR org/apache/http/conn/SchemePortResolver
java.lang.NoClassDefFoundError: org/apache/http/conn/SchemePortResolver
    at com.amazonaws.http.apache.client.impl.ApacheHttpClientFactory.<init>(ApacheHttpClientFactory.java:41)

Removing the stripe library fixes the Amazon one, so I've come to suspect there's some sort of conflict there. My question, is how do I figure out what is causing the issue, and fix it.

I found a similar issue on the repo: https://github.com/mcohen01/amazonica/issues/294

Which was fixed with

[clj-facebook-graph "0.4.0" :exclusions [clj-http]]

But I'd like to know how I'd be able to find out what is in the Stripe library that is causing the issue, and how I can go in and fix it without breaking the library. I'm also interested in more general ideas on how to do this so should I encounter it again I can fix the issue.

2 Answers

If you're using Leiningen, you can use lein deps :tree to print helpful debugging information, and before it prints the dependency tree it will print suggested exclusions to avoid these types of issues:

$ lein deps :tree
...
[com.taoensso/faraday "1.9.0"] -> [com.taoensso/encore "2.67.2"] -> [com.taoensso/truss "1.3.3"]
overrides
[amazonica "0.3.112" :exclusions [com.amazonaws/amazon-kinesis-client com.amazonaws/aws-java-sdk com.amazonaws/dynamodb-streams-kinesis-adapter]] -> [com.taoensso/nippy "2.12.2"] -> [com.taoensso/encore "2.68.0"] -> [com.taoensso/truss "1.3.4"]

Consider using these exclusions:
[amazonica "0.3.112" :exclusions [com.amazonaws/amazon-kinesis-client com.taoensso/truss com.amazonaws/dynamodb-streams-kinesis-adapter com.amazonaws/aws-java-sdk]]
...

In my experience there's still some trial and error involved in excluding the precise transitive conflicts. I've had similar issues with AWS SDK, Jackson, etc.

As it is with problems like that, there is no real silver bullet. The best start to find problems in a leiningen project is to run the deps task. E.g.:

lein deps :tree

Which e.g. in a random project results in the following:

Possibly confusing dependencies found:
[org.clojure/clojurescript "1.9.293"] -> [org.clojure/tools.reader "1.0.0-beta3"]
 overrides
[cljfmt "0.6.0" :exclusions [org.clojure/clojure]] -> [rewrite-cljs "0.4.4"] -> [org.clojure/tools.reader "1.0.5"]
 and
[cljfmt "0.6.0" :exclusions [org.clojure/clojure]] -> [org.clojure/tools.reader "1.2.2"]

Consider using these exclusions:
[cljfmt "0.6.0" :exclusions [org.clojure/clojure org.clojure/tools.reader]]

Those are hints to start from. After that initial block you will see the whole tree of transitive deps. E.g.:

[cljfmt "0.6.0" :exclusions [[org.clojure/clojure]]]
  [com.googlecode.java-diff-utils/diffutils "1.3.0"]
  [org.clojure/tools.cli "0.3.7"]
  [rewrite-clj "0.6.0"]
  [rewrite-cljs "0.4.4"]

And you can try to investigate more from there.

Related