Skip to content
Select theme

How to fix error E0282: type annotations needed

Short answer: a piece of code leaves a type with nothing to pin it to — an empty Vec::new(), a parse() call, a bare collect() — and more than one type would make the code compile, so the compiler refuses to pick. The message headline is always type annotations needed; the code in front of it is E0282, E0283 or E0284 depending on which piece was underdetermined. The fix is the same everywhere: name one concrete type, either on the binding (let v: Vec<i32> = ...) or on the call itself ("42".parse::<u32>()). Unlike E0308, where two known types disagree, E0282 is the absence of a type at all: the compiler is not rejecting what you wrote, it is asking which type you meant.

The everyday version: a collection starts empty, so its element type comes from nowhere.

Compiling that with cargo build prints:

error[E0282]: type annotations needed for `Vec<_>`
--> src/main.rs:2:9
|
2 | let v = Vec::new();
| ^ ---------- type must be known at this point
|
help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
|
2 | let v: Vec<T> = Vec::new();
| ++++++++
For more information about this error, try `rustc --explain E0282`.

The headline says the problem in one line: type annotations needed for `Vec<_>` . A Vec<T> holds elements of type T, and nothing so far says what T is. Printing with {:?} needs the element type to implement Debug — thousands of types do — so the print is not a clue either. When several types would all make the code work, Rust does not guess. It stops and asks.

This prints:

[1, 2]

The : Vec<i32> after the name is the whole fix. Type inference in Rust flows in both directions — from the value to the binding and from the binding to the value — so one annotation anywhere in the chain settles it. Nothing changes at run time; the annotation is checked at compile time and then erased.

Usually you do not even need it, because real use pins the type on its own:

This prints:

[1]

push(1) makes the element type i32, and the whole Vec knows what it is from that moment. The error only bites when the collection is printed, returned, or passed along before anything was put in it. (String::new() never shows this error, because String already names its contents — the annotation is needed exactly when the type has an unspoken parameter: Vec<T>, HashMap<K, V>, HashSet<T>.)

Second shape. parse turns a string into a number — or an IpAddr, or any type that implements FromStr. That “any type” is the problem:

Compiling that with cargo build prints:

error[E0284]: type annotations needed
--> src/main.rs:2:9
|
2 | let guess = "42".parse().expect("not a number");
| ^^^^^ ----- type must be known at this point
|
= note: cannot satisfy `<_ as FromStr>::Err == _`
= note: the type must also implement `FromStr`
note: required by a bound in `core::str::<impl str>::parse`
--> /Users/rango/.rustup/toolchains/1.99.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/str/mod.rs:2782:21
|
2782 | pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
| ^^^^^^^ required by this bound in `core::str::<impl str>::parse`
help: consider giving `guess` an explicit type
|
2 | let guess: /* Type */ = "42".parse().expect("not a number");
| ++++++++++++
For more information about this error, try `rustc --explain E0284`.

The headline is the same type annotations needed — this time with the code E0284. The note says what could not be worked out: cannot satisfy `<_ as FromStr>::Err == _` . In words: parse is declared as fn parse<F: FromStr>(&self) -> Result<F, F::Err>, so choosing the output type also chooses the error type, and nothing in the rest of main chooses either. Printing the value does not pin it down — almost every type implements Display.

Annotate the binding:

This prints:

42

Or put the type on the call, with the turbofish syntax — ::<T> after the method name:

This prints the same 42. Both fixes say the same thing; pick whichever reads better where you are. The turbofish earns its keep when the binding has no natural place for a type — in a match arm, a function argument, a chained expression — or when you want the type visible right where the conversion happens.

Third shape, and the most surprising one. collect() turns an iterator into a collection — but “collection” is not one type:

Compiling that with cargo build prints:

error[E0283]: type annotations needed
--> src/main.rs:2:9
|
2 | let evens = (0..10).filter(|n| n % 2 == 0).collect();
| ^^^^^ ------- type must be known at this point
|
= note: the type must implement `FromIterator<i32>`
note: required by a bound in `collect`
--> /Users/rango/.rustup/toolchains/1.99.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2073:19
|
2073 | fn collect<B: FromIterator<Self::Item>>(self) -> B
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
help: consider giving `evens` an explicit type
|
2 | let evens: Vec<_> = (0..10).filter(|n| n % 2 == 0).collect();
| ++++++++
For more information about this error, try `rustc --explain E0283`.

Again type annotations needed, now with the code E0283. The iterator’s items are i32 — that part is known. What is unknown is the container: the same expression can produce a Vec<i32>, a VecDeque<i32>, a HashSet<i32>, and more, because collect is generic over everything that implements FromIterator. One expression, many valid results — the compiler will not choose for you. Note that the compiler’s own suggestion is exactly the fix:

This prints:

[0, 2, 4, 6, 8]

Or put the container on the call:

This prints the same list. A middle form is common when the element type is already obvious and only the container needs naming: Vec<_> means “a Vec, of whatever the iterator produces” — let evens: Vec<_> = ...collect(); compiles just the same, and the _ is filled in from the iterator.

The same headline travels under three codes, and the difference is where the missing type was sitting:

  • E0282 — the value’s own type parameter is open: type annotations needed for `Vec<_>` . The help: points at the binding.
  • E0283 — a trait bound could be satisfied by several impls: the type must implement `FromIterator<i32>` . The help: suggests a type annotation that names the container.
  • E0284 — an associated type in the chain is unresolved: cannot satisfy `<_ as FromStr>::Err == _` .

Searching for any of the three lands on the same fix: give the compiler one concrete type. The note: lines name the constraint that could not be satisfied; read them if the fix is not obvious, because they say exactly which choice was left open.

  • mismatched types — E0308, two types that were both known and disagree. E0282 is the opposite situation: not enough is known to disagree.
  • the trait bound is not satisfied — E0277. Happens after you fix this one if the type you named does not actually support the operation — parsing into a type with no FromStr impl, for instance.