Dependencies with exclusions apply incorrectly


When a library specifies a dependency with some :exclusions those exclusions are applied even if another library specifies the same dependency without :exclusions.

shadow-cljs in this case depends on ring-core but excludes clj-time.

pedestal.service also depends on ring-core and uses the middleware that requires clj-time but since shadow-cljs excluded it it is not available.

Environment linux


Alex Miller
June 28, 2019, 5:02 PM

Could you give me a more complete dependency tree? I want to make sure I’m understanding the scenario.

Thomas Heller
July 3, 2019, 10:50 AM

I recently learned that this also happens with lein so it may be the default behavior of maven and not something tools.deps related. Regardless here is the additional info.


Here are the dependencies with just clojure+pedestal.service. Note clj-time at line 39.



If I now add shadow-cljs to the deps the clj-time dependency disappears.



Since shadow-cljs declares a dependency on a newer ring-core version (line 82) it seems to be picked alongside the exclusions it declares although pedestal.service does not declare those exclusions (and in fact requires clj-time because of some middleware it uses).

Alex Miller
November 23, 2019, 6:30 AM

I'm going to restate things here for my benefit

With dep pedestal.service 0.5.5 you'll get this (omitting many other libs):

With pedestal.service + shadow-cljs you get:

That is, in the former case ring-core 1.6.3 is picked which includes clj-time. In the latter case, both ring-core 1.6.3 and 1.7.1 are requested by different branches of the deps tree. deps picks the newer one (ring-core 1.7.1), which excludes clj-time, however pedestal.service 0.5.5 actually needs that.

I think this is what I would expect to happen in this scenario and it highlights both the downside of stating constraints (exclusions) and the broken nature of semver. There is no good or general way that deps can understand this situation and produce a result that isn't broken in other cases (generally you don't want transitive deps of non-selected versions). The correct "solution" here is for a human to step in and specify the versions and libs to use to satisfy all branches of the deps tree. What would probably be useful is for deps (or some tool) have some way to detect this scenario and warn/error that something problematic might be happening.

Alex Miller
November 23, 2019, 6:40 AM

Actually, going back to your prior comment, you said "although pedestal.service does not declare those exclusions (and in fact requires clj-time because of some middleware it uses)". So my followup question here would be - what exactly requires clj-time here? pedestal.service? a dep of pedestal.service? a dep or ring-core?

Whatever it is, shouldn't that dep specify java-time as a dep?

Alex Miller
November 24, 2020, 9:49 PM

Following up on the last comment, I think what's happening here is correct and if java-time is really a requirement at a higher level, it should be declaring that dep rather than getting it implicitly via a transitive dep.

Won't Fix




Thomas Heller