RustArena

Rust error E0308: mismatched types

What Rust's E0308 mismatched types error means, how to read expected vs found, and fixes for the most common causes.

E0308 means an expression has a different type from the one the compiler needed at that spot. It's the most common Rust error, and the message always has the same shape: expected X, found Y.

So the fix is either to change the expression to produce the expected type, or to change what you declared.

Cause 1: a semicolon after the return value

fn total(a: i32, b: i32) -> i32 {
    a + b;
}

fn main() {
    println!("{}", total(1, 2));
}
error[E0308]: mismatched types
 --> src/main.rs:1:29
  |
1 | fn total(a: i32, b: i32) -> i32 {
  |    -----                    ^^^ expected `i32`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
2 |     a + b;
  |          - help: remove this semicolon to return this value

"found ()" almost always means a stray semicolon or a missing else. Delete the ;.

Cause 2: mixing number types

Rust never converts numbers implicitly, so i32 + i64, or an i32 passed where a usize is expected, is an error. Convert one side: i64::from(a) + b, or index as usize. (Mixed arithmetic also reports E0277, "cannot add i64 to i32".)

Cause 3: &str vs String

let name: String = "Ferris"; says expected String, found &str. Use "Ferris".to_string() or String::from("Ferris"). The reverse (a String passed to a &str parameter) is fixed by borrowing: greet(&name).

Cause 4: Option or Result used as a plain value

fn main() {
    let scores = vec![10, 20, 30];
    let first: i32 = scores.first();
    println!("{first}");
}
error[E0308]: mismatched types

first() returns Option<&i32> because the vector might be empty. Handle the None case: scores.first().copied().unwrap_or(0), or if let Some(&first) = scores.first() { ... }.

Cause 5: branches of different types

fn main() {
    let lives = 3;
    let label = if lives > 0 { "alive" } else { 0 };
    println!("{label}");
}
error[E0308]: `if` and `else` have incompatible types

Every arm of an if or match used as a value must have the same type. The same goes for match arms.

Cause 6: a reference where a value is expected (or the reverse)

Expected i32, found &i32 happens when iterating with for x in &v and passing x to a function taking i32. Dereference with *x, or iterate with .iter().copied(). Expected &str, found String: add &.

How to fix it fast

  1. Read the expected and found types, and find where the expected type came from (rustc points at it with ---- expected due to this).
  2. Check the help: lines; rustc often suggests the exact conversion (.to_string(), .into(), removing a ;).
  3. If you're unsure of a type, annotate a variable with a wrong type on purpose, like let x: () = value;. The error tells you the real type.

Example

fn total(a: i32, b: i32) -> i32 {
    a + b
}

fn describe(lives: i32) -> String {
    let label = if lives > 0 { "alive" } else { "out" };
    format!("{label} with {lives} lives")
}

fn main() {
    let small: i32 = 7;
    let big: i64 = 5_000_000_000;
    println!("{}", total(1, 2));
    println!("{}", i64::from(small) + big);

    let name: String = "Ferris".to_string();
    println!("{}", describe(3));
    println!("{name} {}", describe(0));

    let scores = vec![10, 20, 30];
    let first: i32 = scores.first().copied().unwrap_or(0);
    let none: Vec<i32> = Vec::new();
    println!("{first} {}", none.first().copied().unwrap_or(0));

    let mut sum = 0;
    for s in &scores {
        sum += *s;
    }
    println!("sum {sum}");
}

Output:

3
5000000007
alive with 3 lives
Ferris out with 0 lives
10 0
sum 60

Practice it