Skip to content

Rust Error E0277: The Trait Bound Is Not Satisfied

Error E0277 means: you used a type in a place that needs an ability the type doesn’t have. Printing it, comparing it, adding it, converting it, sending it to another thread: each of these needs a trait, and your type is missing that trait. It is one of the most common Rust errors, the message usually tells you the exact fix, and most of the time the fix is one line. (This page is part of Rust compiler errors explained.)

The version most people meet first is printing their own struct with {}:

error[E0277]: `Player` doesn't implement `std::fmt::Display`
--> src/main.rs:8:20
|
8 | println!("{}", p);
| -- ^ `Player` cannot be formatted with the default formatter
| |
| required by this formatting parameter
|
help: the trait `std::fmt::Display` is not implemented for `Player`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

The program that causes it:

struct Player {
name: String,
score: u32,
}
fn main() {
let p = Player { name: String::from("Ana"), score: 42 };
println!("{}", p);
}

A trait is a promise that a type can do something. Display is the promise “I know how to print myself nicely”. PartialEq is “I can be compared with ==”. Send is “I am safe to move to another thread”.

Code like println!, .sort(), + and thread::spawn asks for one of those promises. The compiler points at the value you passed (p on line 8) and says: this type never made that promise, so I can’t use it here.

Think of a power socket. The socket only accepts plugs of one shape. Your device may work perfectly, but if its plug doesn’t fit, it doesn’t go in. E0277 is the compiler saying “wrong plug”. You fix it by giving the type the right plug: usually with #[derive(...)], sometimes with a short impl block.

Rust never guesses. For your own Player type, there is no single “right” way to print it, compare it, or sort it. Should two players be equal when their names match, or only when every field matches? Rust makes you say so, instead of quietly doing something you didn’t mean.

The check happens at compile time. In many languages, printing an object you never taught to print gives you something useless like <Player object at 0x7f...>, and sending a non-thread-safe value to a thread gives you a rare crash in production. In Rust, both are compile errors you fix once.

You can read more about how traits work on the Traits page, and about the everyday ones (Debug, Display, PartialEq, Ord, Hash) on Common Traits.

E0277 has many faces. Find the message that matches yours below.

{:?} needs Debug. You almost never write it by hand: add #[derive(Debug)]. Use this for debugging and logs. The {:?} version of the error looks like this:

error[E0277]: `Player` doesn't implement `Debug`
= help: the trait `Debug` is not implemented for `Player`
= note: add `#[derive(Debug)]` to `Player` or manually `impl Debug for Player`

{} needs Display. Rust can’t derive it, because only you know what the “nice” version should look like. Write a small impl with write!. Use this for text your users will see.

use std::fmt;
#[derive(Debug)] // gives you {:?} for free
struct Player {
name: String,
score: u32,
}
// You write Display yourself: this decides what {} prints.
impl fmt::Display for Player {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ({} points)", self.name, self.score)
}
}
fn main() {
let p = Player { name: String::from("Ana"), score: 42 };
println!("{:?}", p);
println!("{}", p);
}

Output:

Player { name: "Ana", score: 42 }
Ana (42 points)
▶ Try it Yourself

Fix 2: Comparing, sorting, or using as a HashMap key

Section titled “Fix 2: Comparing, sorting, or using as a HashMap key”

.contains() and == need PartialEq. .sort() needs Ord. HashSet and HashMap keys need Eq and Hash. The messages look like this:

error[E0277]: can't compare `Point` with `Point`
= help: the trait `PartialEq` is not implemented for `Point`
error[E0277]: the trait bound `Priority: Ord` is not satisfied
= help: the trait `Ord` is not implemented for `Priority`
error[E0277]: the trait bound `Point: Hash` is not satisfied
= help: the trait `Hash` is not implemented for `Point`

The fix is to derive them. They build on each other, so the usual full set is PartialEq, Eq, Hash, PartialOrd, Ord:

use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
enum Priority {
Low,
Medium,
High,
}
fn main() {
let mut tasks = vec![Priority::High, Priority::Low, Priority::Medium];
tasks.sort(); // needs Ord
println!("{:?}", tasks);
println!("Has high: {}", tasks.contains(&Priority::High)); // needs PartialEq
let mut counts: HashMap<Priority, u32> = HashMap::new(); // key needs Eq + Hash
for task in &tasks {
*counts.entry(*task).or_insert(0) += 1;
}
println!("Low tasks: {}", counts[&Priority::Low]);
}

Output:

[Low, Medium, High]
Has high: true
Low tasks: 1
▶ Try it Yourself

A derived Ord sorts enum variants in the order you wrote them, and structs field by field from top to bottom. One honest catch: a type with an f64 field can’t derive Eq, Hash or Ord, because floats have NaN, which isn’t equal to itself. For sorting floats, see Sorting.

Fix 3: Mixing number types (cannot add f64 to i32)

Section titled “Fix 3: Mixing number types (cannot add f64 to i32)”
error[E0277]: cannot add `f64` to `i32`
--> src/main.rs:4:23
|
4 | let total = items + price;
| ^ no implementation for `i32 + f64`
|
= help: the trait `Add<f64>` is not implemented for `i32`

Rust never converts numbers for you, not even i32 to f64. Both sides of +, -, * and / must be the same type. Convert one side yourself with as:

fn main() {
let items: i32 = 3;
let price: f64 = 2.5;
let total = items as f64 * price; // convert first, then multiply
println!("Total: {total}");
}

Output:

Total: 7.5
▶ Try it Yourself

f64::from(items) also works and can never lose data. Going the other way (f64 to i32) cuts off the decimals, so think about rounding first. The Type Casting and Conversions pages cover the details.

error[E0277]: `?` couldn't convert the error to `ConfigError`
|
8 | fn parse_port(text: &str) -> Result<u16, ConfigError> {
| ------------------------ expected `ConfigError` because of this
9 | let port = text.parse::<u16>()?;
| --------------^ the trait `From<ParseIntError>` is not implemented for `ConfigError`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait

When ? hits an error, it returns it from your function. If the error type is different from the one your function promises, ? tries to convert it with From. Your job is to write that From:

use std::num::ParseIntError;
#[derive(Debug)]
enum ConfigError {
BadPort(ParseIntError),
}
// Teach `?` how to turn a ParseIntError into a ConfigError.
impl From<ParseIntError> for ConfigError {
fn from(err: ParseIntError) -> Self {
ConfigError::BadPort(err)
}
}
fn parse_port(text: &str) -> Result<u16, ConfigError> {
let port = text.parse::<u16>()?;
Ok(port)
}
fn main() {
println!("{:?}", parse_port("8080"));
println!("{:?}", parse_port("eighty"));
}

Output:

Ok(8080)
Err(BadPort(ParseIntError { kind: InvalidDigit }))
▶ Try it Yourself

Other good options: convert just one call with .map_err(ConfigError::BadPort)?, use #[from] from the thiserror crate, or return Result<T, Box<dyn std::error::Error>> in small programs. See Custom Errors and anyhow and thiserror.

Fix 5: Rc cannot be sent between threads safely

Section titled “Fix 5: Rc cannot be sent between threads safely”
error[E0277]: `Rc<String>` cannot be sent between threads safely
--> src/main.rs:6:32
|
6 | let handle = thread::spawn(move || {
| ------------- required by a bound introduced by this call
...
= help: within `{closure@src/main.rs:6:32: 6:39}`, the trait `Send` is not implemented for `Rc<String>`

Rc counts its owners with a plain number, which two threads could change at the same time and corrupt. So Rc is not Send. Use Arc (the “atomic” version) instead. It works the same way and is safe across threads:

use std::sync::Arc;
use std::thread;
fn main() {
let config = Arc::new(String::from("debug"));
let for_thread = Arc::clone(&config); // a second owner for the thread
let handle = thread::spawn(move || {
println!("Thread sees: {for_thread}");
});
handle.join().unwrap();
println!("Main still has: {config}");
}

Output:

Thread sees: debug
Main still has: debug
▶ Try it Yourself

The same goes for RefCell: across threads, use Arc<Mutex<T>> instead of Rc<RefCell<T>>. See Shared State and Concurrency.

  • Generic functions. fn announce<T: Display>(item: T) called with your struct gives `Song` doesn't implement `std::fmt::Display` with “required by a bound in announce”. Fix: implement the trait the bound asks for.
  • Tests. assert_eq!(a, b) needs both PartialEq and Debug (to print the values when the test fails). Fix: #[derive(Debug, PartialEq)].
  • .collect() into the wrong type. let nums: Vec<i32> = words.iter().collect(); gives “a value of type Vec<i32> cannot be built from an iterator over elements of type &String”. Fix: convert each item first, for example .map(|w| w.parse().unwrap()). See Iterators.

Quick check

1. You get "Order doesn't implement Debug" when using {:?}. What's the quickest fix?

2. Why does let total = 3_i32 + 2.5_f64; fail?

3. Your thread code fails with "Rc<String> cannot be sent between threads safely". What should you use?

Score: 0 / 3