How to fix error E0277: the trait bound is not satisfied
Short answer: some code required a type to implement a trait, and the compiler could not prove that it does. E0308 is about two types disagreeing; E0277 is about a type and a trait — the type may be exactly what you meant, and the problem is that it cannot do the one thing the code asks of it: be printed, be compared, be sorted, be sent across a thread. The diagnostic names the trait, names the type, and — this is the part to read — points at where the requirement came from. The three common causes below differ in where that requirement lives, and each has a different fix.
The error
Section titled “The error”The everyday version: a type was handed to println! and it has no way to print itself.
struct Point { x: i32, y: i32,}
fn main() { let p = Point { x: 3, y: 7 }; println!("{}", p);}Compiling that with cargo build prints:
error[E0277]: `Point` doesn't implement `std::fmt::Display` --> src/main.rs:8:20 |8 | println!("{}", p); | -- ^ `Point` cannot be formatted with the default formatter | | | required by this formatting parameter |help: the trait `std::fmt::Display` is not implemented for `Point` --> src/main.rs:1:1 |1 | struct Point { | ^^^^^^^^^^^^ = note: in format strings you may be able to use `{:?}` (or `{:#?}` for pretty-print) instead
For more information about this error, try `rustc --explain E0277`.The headline names both sides — the trait std::fmt::Display and the type Point — and the note
underneath says what the code was trying to do: format Point with the default formatter, the one
{} selects. There is nothing wrong with Point. It is a fine struct. It simply never promised to
be printable in that way.
For a struct like this, the promise nobody made is Display — a human-readable, {}-style
rendering — and Display is deliberately not derivable: the compiler cannot guess what a Point
should look like. The cheaper fix is Debug, which is derivable and renders with {:?}:
#[derive(Debug)]struct Point { x: i32, y: i32,}
fn main() { let p = Point { x: 3, y: 7 }; println!("{p:?}");}This prints:
Point { x: 3, y: 7 }Writing impl std::fmt::Display for Point is the other legitimate fix — it buys the {} form, and
it is worth it for types users will print often. What E0277 will not do is pick for you: the error
only says the promise is missing, and only the program can say whether {} or {:?} is the
rendering it meant.
When deriving is the answer
Section titled “When deriving is the answer”The same cause — a trait nobody implemented — wears a different face when the trait is one of the
comparable ones. Sorting a vector needs its elements to implement Ord, and a plain struct does
not:
#[derive(Debug)]struct Person { name: String, age: u8,}
fn main() { let mut people = vec![ Person { name: "Ada".to_string(), age: 36 }, Person { name: "Grace".to_string(), age: 45 }, ]; people.sort(); println!("{:?}", people);}Compiling that with cargo build prints:
error[E0277]: the trait bound `Person: Ord` is not satisfied --> src/main.rs:12:12 | 12 | people.sort(); | ^^^^ the trait `Ord` is not implemented for `Person` |note: required by a bound in `slice::<impl [T]>::sort` --> /Users/rango/.rustup/toolchains/1.99.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/slice.rs:133:12 |131 | pub fn sort(&mut self) | ---- required by a bound in this associated function132 | where133 | T: Ord, | ^^^ required by this bound in `slice::<impl [T]>::sort`help: consider annotating `Person` with `#[derive(Ord)]` | 2 + #[derive(Ord)] 3 | struct Person { |
For more information about this error, try `rustc --explain E0277`.The pointer is on people.sort() — the call site — and the note names where the requirement
lives: required by a bound in `slice::<impl [T]>::sort` , deep in the standard library’s source.
That --> path is where rustup installed the toolchain on this machine; the version directory in
the middle will read as the reader’s own. The struct never heard of sorting; it is sort() that
demands every T it sorts implement Ord — its signature says so right in the note, where T: Ord — and the diagnostic traces the demand from the call back to that signature.
Ord is derivable, and the help: block says exactly that. The derive list gets Ord plus the
traits it builds on — PartialEq, Eq, and PartialOrd:
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]struct Person { name: String, age: u8,}
fn main() { let mut people = vec![ Person { name: "Grace".to_string(), age: 45 }, Person { name: "Ada".to_string(), age: 36 }, ]; people.sort(); println!("{:?}", people);}This prints:
[Person { name: "Ada", age: 36 }, Person { name: "Grace", age: 45 }]Derived Ord compares fields in declaration order — name first, then age — which may or may
not be the order the program means. When it is not, keep the derive anyway if other code needs the
comparison, and sort by the field you mean with people.sort_by_key(|p| p.age). The error was
never about which order; it was about the missing promise.
When the trait can never be implemented
Section titled “When the trait can never be implemented”The third cause is the one where “just implement it” is not an option — because the type is
forbidden from satisfying the trait, and the fix is a different type. The classic is sharing
non-Send data with a thread:
use std::rc::Rc;use std::thread;
fn main() { let data = Rc::new(5); let handle = thread::spawn(move || { println!("{data}"); }); handle.join().unwrap();}Compiling that with cargo build prints:
error[E0277]: `Rc<i32>` cannot be sent between threads safely --> src/main.rs:6:32 | 6 | let handle = thread::spawn(move || { | ------------- ^------ | | | | __________________|_____________within this `{closure@src/main.rs:6:32: 6:39}` | | | | | required by a bound introduced by this call 7 | | println!("{data}"); 8 | | }); | |_____^ `Rc<i32>` cannot be sent between threads safely | = help: within `{closure@src/main.rs:6:32: 6:39}`, the trait `Send` is not implemented for `Rc<i32>`note: required because it's used within this closure --> src/main.rs:6:32 | 6 | let handle = thread::spawn(move || { | ^^^^^^^note: required by a bound in `spawn` --> /Users/rango/.rustup/toolchains/1.99.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/thread/functions.rs:128:8 |125 | pub fn spawn<F, T>(f: F) -> JoinHandle<T> | ----- required by a bound in this function...128 | F: Send + 'static, | ^^^^ required by this bound in `spawn`
For more information about this error, try `rustc --explain E0277`.Read the chain, top to bottom. The headline says Rc<i32> cannot be sent between threads safely —
the trait is Send, and Rc does not implement it on purpose, because its reference counting is
not atomic and concurrent access would corrupt it. The notes then walk the demand from the closure
(required because it's used within this closure) back to thread::spawn (required by a bound in `spawn` ), where the signature shows the line that demanded it: F: Send + 'static. When a bound
fails through several layers, the error is a chain, and each note is one link of it.
This time no help: block offers a replacement — the compiler names the missing trait and stops.
The standard library has the type that does satisfy it: Arc, a reference counter with atomic
operations, built for exactly this:
use std::sync::Arc;use std::thread;
fn main() { let data = Arc::new(5); let handle = thread::spawn(move || { println!("{data}"); }); handle.join().unwrap();}This prints:
5The tell for this cause: the type in the headline is one you did not write and cannot write —
Rc, f64, a type from another crate. Implementing a trait for it is off the table, so the fix is
swapping in a type designed for the job, or restructuring so the trait is never demanded.
When the type is a type parameter
Section titled “When the type is a type parameter”The last cause moves the problem into your own signature. A generic function that prints its
items compiles right up until the compiler asks what T can do:
fn show<T>(items: Vec<T>) { for item in items { println!("{item}"); }}
fn main() { show(vec![1, 2, 3]);}Compiling that with cargo build prints:
error[E0277]: `T` doesn't implement `std::fmt::Display` --> src/main.rs:3:19 |3 | println!("{item}"); | ^^^^^^ `T` cannot be formatted with the default formatter | = note: in format strings you may be able to use `{:?}` (or `{:#?}` for pretty-print) insteadhelp: consider restricting type parameter `T` with trait `Display` |1 | fn show<T: std::fmt::Display>(items: Vec<T>) { | +++++++++++++++++++
For more information about this error, try `rustc --explain E0277`.The headline says T doesn’t implement std::fmt::Display — not any concrete type, because no
concrete type has arrived yet. The function’s own signature is what allowed every T in, and
one of those hypothetical Ts — say, a struct with no Display — would break the body. The
compiler checks the body against all possible Ts and stops on the one that cannot print. The
help: line says it directly: consider restricting the type parameter.
That restriction is the fix — the bound travels with the type parameter:
use std::fmt::Display;
fn show<T: Display>(items: Vec<T>) { for item in items { println!("{item}"); }}
fn main() { show(vec![1, 2, 3]); show(vec!["a", "b"]);}This prints:
123abNow the signature makes the same promise the body relies on: whatever show is called with, it
implements Display. A caller passing a type without it gets E0277 at their line, with the
required by a bound in `show` note pointing back here — the same note this article’s second
section read from the other side.
Telling the three apart
Section titled “Telling the three apart”Read the headline, then the notes, in this order:
- The type is one you wrote (
Point,Person) — the trait is missing on your own type. Derive it if the trait is derivable (Ord,PartialEq,Debug), or implement it if it is not (Display). - The type is not yours and the notes form a chain (
Rc<i32>cannot be sent between threads safely) — the trait cannot be implemented for that type at all. Swap in a type that has the trait (ArcforRc) or restructure. - The type is
T— the bound is missing from your own generic signature. AddT: TheTrait.
The notes decide it. required by a bound in `...` names the function that demanded the trait;
required because it's used within this closure (or ... because it appears within ...) says the
demand traveled through an intermediate type; help: consider restricting type parameter is the
compiler telling you which of the three cases you are in.
Not this error
Section titled “Not this error”the method ... exists for struct ..., but its trait bounds were not satisfied— that is E0599, and it is how a bound failure looks when the trait in question is part of the method’s receiver.HashMap<f64, &str>produces exactly this on.insert(...), because a hash map’s keys must beHashandf64deliberately is not — same underlying problem as theRccase, a different code at the surface.expected X, found Y— E0308, the two-types-disagree error this page’s opening contrasted. If the headline prints two types, the trait bound is not the problem.