Rust Error E0404: Expected Trait, Found Struct or Derive Macro
E0404 means: Rust found the name you wrote, but it isn’t a trait, and only a trait can go in that spot. The spots are impl ___ for Type, a bound like T: ___, and dyn ___ or impl ___. The most common case surprises a lot of people: impl Debug for Point without an import. Debug is in scope, but as the #[derive(Debug)] macro, not as the trait. The other common case is a struct used as if it were a trait, which often happens when you’re used to classes and inheritance. Both are quick to fix. (This page is part of Rust compiler errors explained.)
The error message
Section titled “The error message”error[E0404]: expected trait, found derive macro `Debug` --> src/main.rs:6:6 |6 | impl Debug for Point { // ❌ `Debug` here is the derive macro, not the trait | ^^^^^ not a trait |help: consider importing this trait instead |1 + use std::fmt::Debug; |This is the program that produces it:
struct Point { x: i32, y: i32,}
impl Debug for Point { // ❌ `Debug` here is the derive macro, not the trait fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "Point at ({}, {})", self.x, self.y) }}
fn main() { let p = Point { x: 3, y: 4 }; println!("{:?}", p);}What it means
Section titled “What it means”The ^^^^^ points at Debug on line 6, labelled “not a trait”. The headline says what Rust found instead: a derive macro called Debug.
That’s because there are two things named Debug. The macro Debug, which you use as #[derive(Debug)], is in the prelude, so every file can see it. The trait std::fmt::Debug, which you need for impl Debug for ..., is not in the prelude. So Rust finds the only Debug it can see, notices it’s a macro, and stops. The help line gives the import that brings in the trait. Hash works the same way: expected trait, found derive macro `Hash` , fixed with use std::hash::Hash;.
When the headline says found struct `Animal` (or enum, or type alias), the name is one of your own types, used where a trait belongs.
It’s like asking for “a licensed driver” and being handed a car. A car is a real thing, and closely related, but the job asked for someone who can drive: a set of abilities, which is what a trait is.
Why Rust does this
Section titled “Why Rust does this”Rust separates data from behaviour. A struct or enum describes data: what a value is. A trait describes behaviour: what a type can do. impl Trait for Type connects the two: “this type can do these things”. A bound like T: Trait means “any type that can do these things”.
A struct can’t be used in those places, because it isn’t a list of abilities. And Rust has no inheritance, so impl Animal for Dog can’t mean “Dog is a kind of Animal” when Animal is a struct. If you want several types to share behaviour, the shared part is a trait. See Traits and Generics.
Rust also keeps macros and traits in separate namespaces, which is why Debug can be both a macro and a trait. The derive macro is in the prelude so #[derive(Debug)] works everywhere; the trait only needs to be named when you implement or bound it yourself.
How to fix it
Section titled “How to fix it”Fix 1: Import the trait (use std::fmt::Debug;)
Section titled “Fix 1: Import the trait (use std::fmt::Debug;)”Choose this when the message says found derive macro and you want your own format, or you need the trait in a bound like T: Debug. Add the line from the help:
use std::fmt::Debug;
struct Point { x: i32, y: i32,}
impl Debug for Point { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "Point at ({}, {})", self.x, self.y) }}
fn print_all<T: Debug>(items: &[T]) { for item in items { println!("{:?}", item); }}
fn main() { let p = Point { x: 3, y: 4 }; println!("{:?}", p); print_all(&[Point { x: 0, y: 0 }, Point { x: -1, y: 7 }]);}Output:
Point at (3, 4)Point at (0, 0)Point at (-1, 7)A common alternative is use std::fmt; and then impl fmt::Debug for Point with fmt::Formatter and fmt::Result. Both are fine; pick one style per file.
Fix 2: Use #[derive(Debug)] instead of writing the impl
Section titled “Fix 2: Use #[derive(Debug)] instead of writing the impl”Choose this when you don’t need a custom format, which is most of the time for Debug. The derive macro writes the whole impl Debug for Point for you, and you don’t need any import:
#[derive(Debug)] // ✅ the derive macro writes `impl Debug for Point` for youstruct Point { x: i32, y: i32,}
fn main() { let p = Point { x: 3, y: 4 }; println!("{:?}", p); println!("{:#?}", p); println!("distance from (0, 0) on a grid: {}", p.x.abs() + p.y.abs());}Output:
Point { x: 3, y: 4 }Point { x: 3, y: 4,}distance from (0, 0) on a grid: 7Use one or the other, not both: #[derive(Debug)] plus your own impl Debug gives a “conflicting implementations” error (E0119). {:#?} is the pretty, multi-line form. More in Common Traits.
Fix 3: Define a trait for the shared behaviour
Section titled “Fix 3: Define a trait for the shared behaviour”Choose this when the message says found struct in an impl X for Y line. You probably wanted Dog to be “a kind of Animal”, like a subclass:
error[E0404]: expected trait, found struct `Animal` --> src/main.rs:7:6 |7 | impl Animal for Dog { // ❌ `Animal` is a struct, not a trait | ^^^^^^ not a traitThe program behind it:
struct Animal { name: String,}
struct Dog;
impl Animal for Dog { // ❌ `Animal` is a struct, not a trait fn name(&self) -> String { String::from("Rex") }}
fn main() { println!("{}", Dog.name());}In Rust, the shared part is a trait: a list of methods each type must provide, plus optional default methods. The data stays in each struct:
trait Animal { // ✅ a trait: what every animal can do fn name(&self) -> String;
fn greet(&self) -> String { // a default method format!("Hi, I'm {}!", self.name()) }}
struct Dog;
struct Cat { name: String, // data lives in the struct}
impl Animal for Dog { fn name(&self) -> String { String::from("Rex") }}
impl Animal for Cat { fn name(&self) -> String { self.name.clone() }}
fn main() { println!("{}", Dog.greet()); let tom = Cat { name: String::from("Tom") }; println!("{}", tom.greet());}Output:
Hi, I'm Rex!Hi, I'm Tom!If you only wanted to add methods to one struct, you don’t need a trait at all: write impl Dog { fn name(&self) -> String { ... } }, without for. See Defining a trait.
Fix 4: Take the struct directly, or bound on a trait
Section titled “Fix 4: Take the struct directly, or bound on a trait”Choose this when the error points at a bound like T: Shape or impl Shape, and Shape is your struct:
error[E0404]: expected trait, found struct `Shape` --> src/main.rs:5:16 |5 | fn describe<T: Shape>(item: &T) { // ❌ `Shape` is a struct, not a trait | ^^^^^ not a traitThe program behind it:
struct Shape { sides: u32,}
fn describe<T: Shape>(item: &T) { // ❌ `Shape` is a struct, not a trait println!("a shape");}
fn main() { describe(&Shape { sides: 3 });}A bound says “any type that implements this trait”. If the function only ever gets a Shape, drop the generic and take &Shape. If it should work for many types, put the shared behaviour in a trait and bound on that:
struct Shape { sides: u32,}
fn describe(item: &Shape) { // ✅ take the struct itself, no generic needed println!("a shape with {} sides", item.sides);}
trait Named { // ✅ or a trait, for "any type that has a name" fn name(&self) -> String;}
impl Named for Shape { fn name(&self) -> String { match self.sides { 3 => String::from("triangle"), 4 => String::from("square"), n => format!("{}-gon", n), } }}
fn shout<T: Named>(item: &T) { // ✅ a trait bound needs a trait println!("{}!", item.name().to_uppercase());}
fn main() { let t = Shape { sides: 3 }; describe(&t); shout(&t); shout(&Shape { sides: 6 });}Output:
a shape with 3 sidesTRIANGLE!6-GON!Trait bounds are explained in Generics and Traits.
Where you’ll usually see it
Section titled “Where you’ll usually see it”impl Vec<i32> as a parameter type. fn total(x: impl Vec<i32>) gives expected trait, found struct `Vec` . impl in that spot needs a trait. Fix: take &[i32] or Vec<i32>, or impl IntoIterator<Item = i32> if you want to accept any collection.
Box<dyn String>. dyn also needs a trait, so this gives expected trait, found struct `String` , and rustc suggests ToString. Fix: Box<dyn ToString> if you meant “anything that can become a string”, or just String. See Trait Objects.
A type alias for a trait. type Printable = dyn std::fmt::Display; followed by impl Printable for A gives expected trait, found type alias `Printable` with the label “type aliases cannot be used as traits”. Fix: write the trait’s real name in the impl.
Related errors
Section titled “Related errors”- E0405: cannot find trait in this scope: the name doesn’t exist at all, like
Displaywithout an import. E0404 means the name exists but is the wrong kind. - E0277: the trait bound is not satisfied: the trait is right, but the type doesn’t implement it.
- E0425: cannot find value in this scope: the same kind of “not found” error for values, functions and types.
- E0107: wrong number of generic arguments: the trait or type is right, but has too many or too few
<...>arguments. - E0119: conflicting implementations:
#[derive(Debug)]and your ownimpl Debugon the same type. - All compiler errors explained
Quick check
Section titled “Quick check”Quick check
1. impl Debug for Point gives "expected trait, found derive macro Debug". What's the simplest fix if you want a custom format?
2. You have struct Animal and write impl Animal for Dog. What does Rust want instead?
3. Which of these can go after T: in fn show<T: ___>(x: T)?
Score: 0 / 3
Read more
Section titled “Read more”- E0404 — Rust error codes index: the official explanation, with the struct-used-as-a-trait example.
- Defining Shared Behavior with Traits — The Rust Book: defining a trait, implementing it, and using it as a bound.
std::fmt::Debug— standard library docs: derivingDebugversus implementing it by hand.- Traits — Rust by Example: a trait shared by several types, with default methods.
std::prelude— standard library docs: what’s in scope in every file, including theDebugderive macro but not the trait.