Fix E0782: Conflicting implementations of trait
Rust’s trait system is one of the most powerful features of the language, enabling expressive abstractions and generic programming. However, the compiler enforces strict coherence rules to ensure that trait implementations remain unambiguous. Error code E0782 signals that you have defined two implementations of the same trait for identical type parameters, or that your implementation conflicts with one that already exists in scope. This violates the core guarantee that at most one implementation of a trait for a given type should ever be applicable.
1. Symptoms
When the Rust compiler encounters conflicting trait implementations, it halts compilation and emits a diagnostic message that points directly to the offending code. The error message is explicit and includes the names of the conflicting types.
Typical compiler output looks like this:
error[E0782]: conflicting implementations of trait `MyTrait` for type `MyStruct`
--> src/lib.rs:15:1
|
15 | impl MyTrait for MyStruct { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyStruct`
|
note: conflicting implementation defined here
--> src/lib.rs:10:1
|
10 | impl MyTrait for MyStruct { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
In more complex scenarios involving generic types, the error message may include additional context about the type parameters:
error[E0782]: conflicting implementations of trait `Iterator` for type `Wrapper<T>`
--> src/iter.rs:42:1
|
42 | impl<T> Iterator for Wrapper<T> { type Item = T; fn next(&mut self) -> Option<T> { None } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<T>`
|
note: upstream crate cannot implement this trait for a type local to this crate
--> src/iter.rs:42:1
|
42 | impl<T> Iterator for Wrapper<T> { type Item = T; fn next(&mut self) -> Option<T> { None } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may also see the error surface when importing a third-party crate that implements a trait for a type you also implemented:
error[E0782]: conflicting implementations of trait `Serialize` for type `Config`
--> src/serialize.rs:8:1
|
8 | impl Serialize for Config { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer { ... } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Config`
The compiler points to both locations where the trait is implemented, making it straightforward to identify which two blocks of code are in conflict.
2. Root Cause
The root cause of error E0782 lies in Rust’s coherence rules, which govern which crates are permitted to implement traits for types. The compiler is designed with a fundamental constraint: for any given type and trait combination, there must be exactly one unambiguous implementation in scope at any point during compilation. This rule exists to preserve soundness in the type system and to prevent the possibility of calling a method and getting different behavior depending on which implementation the compiler happens to choose.
Conflicting implementations fall into several distinct categories. The most straightforward case is a literal duplicate implementation where the same impl Trait for Type block appears twice in your code. This typically results from copy-pasting code and forgetting to update the type names or from generating boilerplate automatically without checking for existing implementations.
A more subtle conflict arises when you implement a trait for a type that already has an implementation from an upstream dependency. Rust’s orphan rules restrict local crates from implementing external traits on external types, but they permit local crates to implement either a local trait on an external type or an external trait on a local type. When a crate defines a struct and a trait simultaneously, and both are considered “local,” you may attempt to implement that trait for that type in a way that clashes with another implementation in a different module or brought in through a dependency.
Generic implementations create another dimension of potential conflict. If your code contains overlapping generic bounds where two separate impl blocks could match the same type due to how Rust’s trait resolution works, the compiler rejects both implementations as conflicting. This often happens when attempting to implement blanket traits in ways that are too broad and inadvertently cover the same ground as another blanket implementation.
Conflicting implementations can also emerge during incremental compilation or when feature-gated code produces duplicate implementations that the compiler cannot distinguish. In these cases, the conflict is structural rather than semantic—it arises from the textual layout of your code rather than an explicit logical contradiction.
3. Step-by-Step Fix
The appropriate fix depends on which category of conflict you are encountering. The following approaches address each scenario systematically.
Fix: Remove Duplicate Implementations
If you have accidentally written the same implementation twice, delete the duplicate. Open your source file and locate both implementations of the trait for the identical type.
Before:
trait MyTrait {
fn do_something(&self);
}
struct MyStruct;
impl MyTrait for MyStruct {
fn do_something(&self) {
println!("First implementation");
}
}
impl MyTrait for MyStruct {
fn do_something(&self) {
println!("Second implementation");
}
}
After:
trait MyTrait {
fn do_something(&self);
}
struct MyStruct;
impl MyTrait for MyStruct {
fn do_something(&self) {
println!("Single unambiguous implementation");
}
}
Fix: Rename Conflicting Types
If you intended to have two different types but inadvertently used the same name, rename one type to disambiguate them. This situation commonly occurs when working with nested modules or type aliases.
Before:
mod outer {
pub struct Item;
pub trait Valuable { fn value(&self) -> i32; }
impl Valuable for Item {
fn value(&self) -> i32 { 42 }
}
}
use outer::Item;
impl outer::Valuable for Item {
fn value(&self) -> i32 { 100 }
}
After:
mod outer {
pub struct Item;
pub trait Valuable { fn value(&self) -> i32; }
impl Valuable for Item {
fn value(&self) -> i32 { 42 }
}
}
use outer::Item;
// No conflicting implementation—Item is already implemented
println!("{}", Item.value());
Fix: Restrict Blanket Implementations
When a blanket implementation overlaps with a more specific one, you must narrow the scope of the blanket implementation using additional trait bounds to exclude the conflicting case.
Before:
trait Transform<T> {
fn transform(self) -> T;
}
impl<T> Transform<T> for Vec<T> {
fn transform(self) -> T where T: Default { T::default() }
}
// This conflicts because Vec<i32> matches the blanket impl above
impl Transform<i32> for Vec<i32> {
fn transform(self) -> i32 { self.into_iter().sum() }
}
After:
trait Transform<T> {
fn transform(self) -> T;
}
// Use a marker trait to exclude specialized types
trait CannotTransform {}
impl<T> CannotTransform for Vec<T> where T: Default {}
impl<T> Transform<T> for Vec<T>
where
T: Default,
Vec<T>: CannotTransform,
{
fn transform(self) -> T { T::default() }
}
// Now this specific impl is allowed
impl Transform<i32> for Vec<i32> {
fn transform(self) -> i32 { self.into_iter().sum() }
}
Fix: Use a Newtype Pattern to Avoid Orphan Conflicts
If you need different trait behavior than what an upstream crate provides, wrap the external type in a local newtype so that you control the implementation space.
Before:
// Third-party crate provides Display for Config, but you want custom formatting
use external_crate::Config;
// This will conflict if external_crate already implements Display for Config
impl std::fmt::Display for Config {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Custom: {}", self.name)
}
}
After:
use external_crate::Config;
// Wrap in a newtype to create a local type you fully control
pub struct ConfigView<'a>(&'a Config);
impl std::fmt::Display for ConfigView<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Custom: {}", self.0.name)
}
}
Fix: Use Feature Flags or Conditional Compilation
If duplicate implementations arise from feature-gated code generating conflicting definitions, use separate conditional compilation blocks that produce one implementation at a time rather than multiple implementations simultaneously.
Before:
#[cfg(feature = "serde")]
impl Serialize for MyData { ... }
#[cfg(feature = "serde")]
impl Serialize for MyData { ... } // Duplicate when same feature applies
After:
#[cfg(feature = "serde_v1")]
impl Serialize for MyData { ... }
#[cfg(feature = "serde_v2")]
impl Serialize for MyData { ... }
#[cfg(all(feature = "serde_v1", not(feature = "serde_v2")))]
impl Serialize for MyData { ... }
4. Verification
After applying any of the fixes described above, verify that the error has been resolved by running the Rust compiler on the affected crate. Execute the following command to perform a full compilation check:
cargo build
A successful build will produce no output for the E0782 error code, and the compilation process will complete without diagnostic messages about conflicting implementations. If your fix involves generic types or trait bounds, also run the test suite to confirm that the trait implementations behave correctly at runtime:
cargo test
For more thorough validation involving complex trait interactions, run cargo check with additional strictness flags to surface any subtle conflicts that might not appear in a standard build:
cargo check --all-features -Zunstable-options
You should also verify that the trait implementations cover the expected types by writing unit tests that exercise each implementation path explicitly. This is especially important when using the newtype pattern or conditional compilation, where it is easy to accidentally leave one code path untested.
5. Common Pitfalls
One of the most frequent mistakes when encountering E0782 is assuming that the compiler will automatically disambiguate between implementations based on specificity. Unlike some languages that perform “most specific match” resolution at call sites, Rust enforces a strict rule that implementations must be non-overlapping at the type level. The compiler performs no runtime analysis to determine which implementation is more appropriate for a given situation.
Another common pitfall involves using glob imports that bring trait implementations into scope unexpectedly. When you write use some_crate::*;, you may inadvertently load implementations that conflict with ones you are about to write. Prefer explicit imports over glob imports in code that defines trait implementations to maintain clarity about which implementations are active.
Copying code from Stack Overflow or example repositories without checking whether the same trait is already implemented in your project is another source of E0782 errors. Always audit existing implementations before adding new ones, particularly when working in large codebases where multiple authors may have independently implemented the same trait for the same type.
When using procedural macros that generate implementations automatically, ensure that the macro output does not produce duplicate implementations across multiple invocations. Some macro configurations with default flags generate implementation code on every use, leading to conflicts that are difficult to trace back to the macro invocation site. Consult the macro’s documentation to understand whether you need to use caching flags or configuration options to prevent redundant code generation.
Finally, be cautious when adding dependencies that transitively bring new trait implementations into scope. A dependency that seemed harmless at the time of addition might define an implementation for a type you are already implementing, causing E0782 errors in code that has not changed recently. When this happens, you may need to refactor your implementation to use a newtype or to remove the conflicting dependency.
6. Related Errors
Error E0119 concerns conflicting implementations arising from a nominal implementation and a blanket implementation that overlap. While E0782 covers general conflicts including literal duplicates, E0119 is specifically triggered when a specific impl Trait for Type block and a more general impl<T> Trait for T where ... block could both apply to the same type. The distinction matters because E0119 is accompanied by a more descriptive message about the interaction between nominal and blanket implementations.
Error E0368 appears when an implementation has the wrong number of type or const parameters for the trait being implemented. Although this error originates from a different class of trait system violations, it often surfaces in the same code regions where developers are experimenting with generic trait implementations, leading to confusion about which error code is actually being reported.
Error E0053 occurs when a method’s signature in a trait implementation does not match the signature declared in the trait definition. This is a signature mismatch error rather than a conflict error, but developers working on complex trait implementations sometimes encounter both errors simultaneously when attempting to resolve E0782 by modifying implementation signatures.