How to fix Rust E0271 type mismatch resolving associated type

Fix Rust E0271 by aligning the actual type's associated type with the trait bound's expected type.

The contract broke

You're writing a generic function that processes a collection. You pass in a vector iterator. The compiler rejects the code with E0271. The error message mentions "type mismatch resolving associated type." You look at your code. The types seem related. The function expects a String, and you're passing strings. Yet the compiler refuses to compile.

The confusion usually stems from the gap between what a trait promises and what a concrete type delivers. Rust traits can define associated types. These are types that the trait implementation must specify. When you write a bound like T: Iterator<Item = String>, you are making a contract. You are saying the type T must implement Iterator, and the Item associated type must be exactly String. E0271 fires when the actual type you pass implements the trait, but its associated type does not match the requirement in the bound.

Associated types define the output

Traits describe behavior. Associated types describe the data involved in that behavior. The Iterator trait is the classic example. Every iterator yields values, but the type of those values depends on the iterator. A Vec<i32> yields i32. A HashMap<String, u32> yields (String, u32). The trait cannot hardcode the item type. Instead, it defines an associated type called Item. Each implementation fills in the blank.

/// A trait that defines a type of output.
trait Producer {
    /// The type this producer yields.
    type Output;

    /// Produce a value of the associated type.
    fn produce(&self) -> Self::Output;
}

/// A producer that yields text.
struct TextProducer;

impl Producer for TextProducer {
    // The associated type is String.
    type Output = String;

    fn produce(&self) -> String {
        "hello".to_string()
    }
}

/// A producer that yields numbers.
struct NumberProducer;

impl Producer for NumberProducer {
    // The associated type is i32.
    type Output = i32;

    fn produce(&self) -> i32 {
        42
    }
}

When you constrain a generic parameter, you can lock the associated type. The constraint T: Producer<Output = String> means T must be a Producer and its Output must be String. If you pass NumberProducer, the compiler sees Output = i32. The contract breaks. E0271 is the compiler telling you the associated type in the implementation does not match the associated type in the bound.

Minimal example

This example shows the error in isolation. The function demands a Producer that outputs String. The call site provides a Producer that outputs i32.

/// Process a value that is guaranteed to be a String.
fn process_text<T: Producer<Output = String>>(p: T) {
    let text = p.produce();
    println!("Got text: {}", text);
}

fn main() {
    let num = NumberProducer;
    // E0271: type mismatch resolving `<NumberProducer as Producer>::Output == String`
    // expected struct `String`, found `i32`
    process_text(num);
}

The error message points to the mismatch. It resolves <NumberProducer as Producer>::Output and finds i32. The bound requires String. The types do not match. The fix is either to change the bound to accept i32, or to change the argument to a type that produces String.

Read the associated type, not just the trait name. The trait match is often correct. The failure is almost always in the associated type constraint.

Reading the error

E0271 messages follow a pattern. The compiler identifies the trait, the associated type, the expected type, and the found type.

error[E0271]: type mismatch resolving `<NumberProducer as Producer>::Output == String`
  --> src/main.rs:18:5
   |
18 |     process_text(num);
   |     ^^^^^^^^^^^^ expected `String`, found `i32`

Break the message down. <NumberProducer as Producer>::Output is the path to the associated type. The compiler is checking the Output of NumberProducer when viewed as a Producer. The result is i32. The bound asked for String. The mismatch is clear.

Sometimes the error involves references. You might see expected String, found &String. Or expected &str, found String. These are also E0271 errors. The associated type includes the reference. &String is not String. &str is not String. The types must match exactly, or you must use a bound that accepts the actual type.

Real world: Iterators and references

The most common source of E0271 is iterators. Collections provide multiple iterator methods. Each method yields a different item type. iter() yields references. into_iter() yields owned values. iter_mut() yields mutable references.

/// Sum the lengths of strings in an iterator.
/// This function takes ownership of the strings.
fn sum_lengths<I: Iterator<Item = String>>(iter: I) -> usize {
    iter.map(|s| s.len()).sum()
}

fn main() {
    let data = vec!["a".to_string(), "b".to_string()];

    // E0271: expected `String`, found `&String`
    // data.iter() yields &String, not String.
    // sum_lengths(data.iter());

    // Fix: Use into_iter() to yield owned Strings.
    let total = sum_lengths(data.into_iter());
    println!("Total length: {}", total);
}

data.iter() returns an iterator where Item = &String. The bound requires Item = String. The reference is the mismatch. into_iter() consumes the vector and yields String. The types align.

The community convention is to prefer iter() when possible. Borrowing avoids allocation and allows reuse. Write functions that accept references when you don't need ownership. If the function only needs to read the strings, change the bound to Item = &String or Item: AsRef<str>. This makes the function more flexible and avoids forcing callers to move data.

Why associated types exist

Rust could have used generic parameters for this. The Iterator trait could be Iterator<Item>. Then you would write Vec<i32>: Iterator<i32>. This works, but it makes syntax verbose. Every use of the trait requires specifying the item type. Associated types let the type determine the item. You write Vec<i32>: Iterator. The compiler infers the item from the implementation.

This design choice simplifies code but introduces E0271. When you constrain a trait, you must be precise about the associated type. The compiler cannot guess that you want &String when you wrote String. It enforces the contract strictly. This strictness prevents subtle bugs where a function assumes a type and receives a reference instead.

Associated types also enable traits to define multiple related types. The Iterator trait has Item. The FromIterator trait has Item. The Deref trait has Target. These types are part of the trait's interface. Bounds can constrain them independently. E0271 ensures the constraints hold.

Pitfalls and fixes

References are the primary pitfall. iter() returns references. Functions often expect owned values. The mismatch triggers E0271.

Another pitfall is &str versus String. A function might expect Item = &str. An iterator over Vec<String> yields &String. &String is not &str. You need an adapter to convert the item type.

/// Count words that start with a specific letter.
/// Accepts iterators yielding string slices.
fn count_starts_with<I: Iterator<Item = &str>>(iter: I, letter: char) -> usize {
    iter.filter(|s| s.starts_with(letter)).count()
}

fn main() {
    let words = vec!["rust".to_string(), "is".to_string(), "cool".to_string()];

    // E0271: expected `&str`, found `&String`
    // count_starts_with(words.iter(), 'r');

    // Fix: Map to &str using as_str.
    let count = count_starts_with(words.iter().map(|s| s.as_str()), 'r');
    println!("Count: {}", count);
}

map transforms the item type. words.iter() yields &String. map(|s| s.as_str()) yields &str. The bound is satisfied.

Use map to adapt item types when the structure is correct but the value type needs conversion. This is a common pattern when working with iterators and trait bounds.

Convention aside: The community prefers where clauses for complex bounds. Writing fn foo<T: Iterator<Item = String>>(...) works, but fn foo<T>(...) where T: Iterator<Item = String> keeps the signature readable. Use where when the bound is long or when you have multiple bounds.

Decision matrix

Use a looser bound when the function does not require a specific associated type. If you only need the item to implement Display, write T: Iterator<Item: Display>. This accepts any iterator whose items can be printed.

Use into_iter() when the function requires owned values and you have a collection. This consumes the collection and yields owned items.

Use iter() when the function accepts references and you want to avoid cloning. This borrows the collection and yields references.

Use map to adapt the item type when the iterator yields the wrong type but can be converted. This transforms the associated type without changing the collection.

Use a trait object when you need dynamic dispatch and the associated type is fixed. Box<dyn Iterator<Item = String>> works when you cannot use generics.

Use a wrapper type when you need to change the associated type permanently. Define a new struct that implements the trait with the desired associated type.

Where to go next