Rust Error E0119 Conflicting Implementations of Trait
E0119 means two impl blocks could apply to the same type. See the common triggers, such as blanket impls and derive plus manual impl, and how to resolve them.

error[E0119]: conflicting implementations of trait ... for type ... means two impl blocks could both apply to the same type, and Rust refuses to pick one. It is most often triggered by a blanket implementation, an impl<T: Something> Trait for T, that overlaps with a specific one such as impl Trait for String. Other languages with similar features resolve the overlap by taking the most specific implementation; stable Rust does not, because that feature, specialization, is not available. The fixes all work by making the two implementations disjoint, so that no type can match both. This post reproduces the error with Rust 1.99, shows two ways to remove the overlap with a program that runs, and lists the other shapes of the same conflict.
The error
Start with a trait, a blanket implementation for everything printable with Debug, and a special case for String:
trait Describe {
fn describe(&self) -> String;
}
impl<T: std::fmt::Debug> Describe for T {
fn describe(&self) -> String {
format!("{self:?}")
}
}
impl Describe for String {
fn describe(&self) -> String {
format!("text: {self}")
}
}error[E0119]: conflicting implementations of trait `Describe` for type `String`
--> b119.rs:11:1
|
5 | impl<T: std::fmt::Debug> Describe for T {
| --------------------------------------- first implementation here
...
11 | impl Describe for String {
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `String`String implements Debug, so the blanket implementation on line 5 already applies to it. The second block on line 11 is another implementation of Describe for the same type. When code calls "x".to_string().describe(), the compiler would have to choose between the two, and the language has no rule for that, so it rejects the program at the point where the overlap first becomes possible, not at the call. The error message points at both blocks, and the type that sits in the overlap.
Why Rust does not pick the more specific one
The idea of letting the narrower impl win is called specialization, and it exists as an unstable nightly feature. It has been difficult to make sound, because lifetimes in a type can affect which impl applies but are erased before code generation, and a "more specific" impl can silently change behavior when someone adds a trait implementation in another crate. Until it is solved, stable Rust requires coherence: for any type and trait, at most one implementation can apply, and the compiler proves it at the declaration site. That is stricter than C++ templates or Haskell's overlapping instances, and the reward is that adding an unrelated crate to your dependency tree can never change which implementation your code uses.
Fix one: make the blanket impl narrower
The conflict goes away if the blanket implementation does not cover String. The standard technique is a marker trait: apply the blanket impl to a local trait that lists exactly the types you want, and String is simply absent.
use std::fmt::Debug;
trait Describe {
fn describe(&self) -> String;
}
// Fix 1: narrow the blanket impl with a marker trait the special case does not implement.
trait DebugDescribe: Debug {}
impl DebugDescribe for i32 {}
impl DebugDescribe for bool {}
impl DebugDescribe for Vec<u8> {}
impl<T: DebugDescribe> Describe for T {
fn describe(&self) -> String {
format!("{self:?}")
}
}
impl Describe for String {
fn describe(&self) -> String {
format!("text: {self}")
}
}
// Fix 2: one method with a default that types can override, instead of two competing impls.
trait Label {
fn label(&self) -> String
where
Self: Debug,
{
format!("{self:?}")
}
}
impl Label for u8 {}
impl Label for &str {
fn label(&self) -> String {
format!("text: {self}")
}
}
fn main() {
println!("{}", 5.describe());
println!("{}", true.describe());
println!("{}", "hi".to_string().describe());
println!("{}", 7u8.label());
println!("{}", "hi".label());
}5
true
text: hi
7
text: hiPart one of the program defines DebugDescribe, an empty trait with Debug as a supertrait, and implements it for i32, bool and Vec<u8>. The blanket impl is now impl<T: DebugDescribe> Describe for T, which applies only to those three. String implements Describe by its own block with no overlap, and the compiler accepts both. The output confirms both paths: 5 and true go through the blanket and "hi".to_string().describe() goes through the specific one, printing text: hi. The cost of the technique is a line per type to opt in. If the blanket should cover everything, the opposite design is better.
Fix two: one trait with a default, overridden where needed
If what you want is "a sensible default, with different behavior for a few types", a default method on the trait expresses that without two competing implementations. The second part of the same program defines Label with a default body and lets individual types override it:
trait Label {
fn label(&self) -> String
where
Self: Debug,
{
format!("{self:?}")
}
}
impl Label for u8 {} // uses the default
impl Label for &str { // overrides it
fn label(&self) -> String {
format!("text: {self}")
}
}7u8.label() prints 7 through the default and "hi".label() prints text: hi through the override. No blanket exists, so no conflict can arise. Each type that wants the default writes an empty impl Label for T {}, which is cheap, and the choice is visible. Most overlapping-impl problems are really this: there was never a need for a blanket implementation, only for a default.
Other shapes of the same conflict
The same error appears when the overlap is less obvious. Two blanket impls with different bounds, impl<T: Display> Foo for T and impl<T: Debug> Foo for T, conflict, because a type can be both. The compiler considers what types could implement the bounds, including types in other crates, and since neither bound excludes the other, they overlap. An implementation for a type and for a reference to it, impl Foo for Meters and impl<T: Foo> Foo for &T, is fine and common, because Meters and &Meters are different types. A conflict between your implementation and one in the standard library arises when the library has a blanket you did not know about: implementing From<Ids> for Ids, or Into, collides with the standard impl<T> From<T> for T, and implementing ToString for a type that implements Display collides with the blanket impl<T: Display> ToString for T. The message names the library implementation, with a path into the standard library, and the fix is to drop yours.
There is also a conflict that looks like E0119 but comes from a future-compatibility rule. The compiler refuses impl Foo for T where T: Bar plus impl Foo for Local if some upstream crate might one day add impl Bar for Local. The note says "upstream crates may add a new impl of trait Bar for type Local in future versions". Fix it by implementing the trait in a way that cannot overlap, usually by moving the bound to a local trait as in fix one.
Which fix to pick
| Intent | Use |
|---|---|
| A default behavior for most types, different for a few | A trait with a default method and per-type overrides |
| One implementation for all types with some property | The blanket impl, with no special cases |
| A closed list of types sharing an implementation | A local marker trait and a blanket on that marker |
| Different behavior for a foreign type | A newtype that wraps it; see E0117 |
| Two sources of the same trait bound overlapping | Remove one, or combine them into one trait |
When the compiler's complaint is that your impl conflicts with one in core, alloc or std, you can almost always delete yours, since the library already provides the behavior. Blanket implementations covers how they work and where their coherence limits sit, and the orphan rule is the companion constraint on which impls you may write at all.


