- Reference
- 27 errors
Rust compiler errors, explained
Each entry is the smallest program that triggers one code, the real output, and the fix that compiles. Re-checked on every build.
Ownership and moves 5
A value has one owner. These fire when you gave it away, or never had it.
E0382Use of a moved value
You handed a value to someone else — another variable, a function call — and then tried to use it again. In Python both names would point at the same object. In Rust the value has exactly one owner, and giving it away ends your claim to it.
error[E0382]: borrow of moved value: `prompt` --> src/main.rs:4:16 | 2 | let prompt = String::from("Summarise this contract"); | ------ move occurs because `prompt` has type `String`, which does not implement the `Copy` trait 3 | let sent = prompt; | ------ value moved here 4 | println!("{prompt} {sent}"); | ^^^^^^ value borrowed here after move | help: consider cloning the value if the performance cost is acceptable | 3 | let sent = prompt.clone(); | ++++++++
The usual fix. Borrow instead of move (&prompt), clone if you really need two copies, or restructure so the second use comes first.
Taught in: 4.2 Handing over the key
E0384Assigned twice to an immutable variable
Variables are immutable unless you say otherwise. Rust makes the decision to change a value visible at the declaration, so a reader never has to scan a function to learn what can move.
error[E0384]: cannot assign twice to immutable variable `tokens_left` --> src/main.rs:3:5 | 2 | let tokens_left = 4096; | ----------- first assignment to `tokens_left` 3 | tokens_left = 4000; | ^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable | help: consider making this binding mutable | 2 | let mut tokens_left = 4096; | +++
The usual fix. Add mut to the declaration, or — often better — shadow the name with a new let.
Taught in: 2.2 Values that change
E0505Moved out while it was still borrowed
A reference to the value is still going to be used later, and you moved the value away. The reference would point at something that no longer belongs to you.
error[E0505]: cannot move out of `prompt` because it is borrowed --> src/main.rs:4:17 | 2 | let prompt = String::from("p"); | ------ binding `prompt` declared here 3 | let r = &prompt; | ------- borrow of `prompt` occurs here 4 | let moved = prompt; | ^^^^^^ move out of `prompt` occurs here 5 | println!("{r} {moved}"); | - borrow later used here | help: consider cloning the value if the performance cost is acceptable | 3 | let r = &prompt.clone(); | ++++++++
The usual fix. Use the reference before the move, or borrow instead of moving.
E0507Cannot move out of a borrow
You have a reference to a struct and tried to take one of its owned fields out. The struct still belongs to its owner; you cannot walk off with a piece of it.
error[E0507]: cannot move out of `d.text` which is behind a shared reference --> src/main.rs:6:5 | 6 | d.text | ^^^^^^ move occurs because `d.text` has type `String`, which does not implement the `Copy` trait | help: consider cloning the value if the performance cost is acceptable | 6 | d.text.clone() | ++++++++
The usual fix. Return a reference (&d.text), clone the field, or take the whole struct by value.
E0381Used a possibly-uninitialised variable
Rust has no “default zero” — a variable must be given a value on every path before it is read.
error[E0381]: used binding `n` isn't initialized --> src/main.rs:3:16 | 2 | let n: i32; | - binding declared here but left uninitialized 3 | println!("{n}"); | ^ `n` used here but it isn't initialized | help: consider assigning a value | 2 | let n: i32 = 42; | ++++
The usual fix. Initialise it where it is declared, or make sure every branch assigns it.
Borrowing and mutability 4
Many readers or one writer, never both, and only if you said mut.
E0502Mutable borrow while an immutable borrow is alive
Someone is still reading through a reference while you try to change the thing they are reading. In Python this is the “list changed size during iteration” bug — Rust refuses to compile it instead of corrupting it at run time.
error[E0502]: cannot borrow `history` as mutable because it is also borrowed as immutable --> src/main.rs:4:5 | 3 | let first = &history[0]; | ------- immutable borrow occurs here 4 | history.push(String::from("again")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here 5 | println!("{first}"); | ----- immutable borrow later used here
The usual fix. Finish using the shared reference before you mutate, or copy out what you need first (.clone() the element).
Taught in: 4.3 Borrowing
E0499Two mutable borrows at once
At any moment you may have many readers or exactly one writer — never two writers. It is the rule that makes data races impossible, and it is checked before the program runs.
error[E0499]: cannot borrow `cache` as mutable more than once at a time --> src/main.rs:4:13 | 3 | let a = &mut cache; | ---------- first mutable borrow occurs here 4 | let b = &mut cache; | ^^^^^^^^^^ second mutable borrow occurs here 5 | a.push('x'); | - first borrow later used here
The usual fix. Use the first &mut to completion before taking the second, or split the data so each writer owns a different piece.
Taught in: 4.4 Borrowing to change
E0596Borrowed an immutable value as mutable
The method needs &mut self — it changes the value — but the binding was never declared mut.
error[E0596]: cannot borrow `history` as mutable, as it is not declared as mutable --> src/main.rs:3:5 | 3 | history.push(String::from("x")); | ^^^^^^^ cannot borrow as mutable | help: consider changing this to be mutable | 2 | let mut history = Vec::<String>::new(); | +++
The usual fix. Declare the binding with let mut.
E0594Assigned to a field of an immutable binding
Same idea as E0384, one level down: the struct is immutable, so none of its fields can be reassigned.
error[E0594]: cannot assign to `cfg.max_tokens`, as `cfg` is not declared as mutable --> src/main.rs:7:5 | 7 | cfg.max_tokens = 200; | ^^^^^^^^^^^^^^^^^^^^ cannot assign | help: consider changing this to be mutable | 6 | let mut cfg = Config { max_tokens: 100 }; | +++
The usual fix. Make the whole binding mut.
Lifetimes 4
A reference cannot outlive the thing it points at.
E0597Borrowed value does not live long enough
A reference outlived the thing it points at. Python would keep the object alive for you; Rust frees it at the closing brace, so the reference would dangle.
error[E0597]: `reply` does not live long enough --> src/main.rs:5:19 | 4 | let reply = String::from("a short-lived reply"); | ----- binding `reply` declared here 5 | longest = &reply; | ^^^^^^ borrowed value does not live long enough 6 | } | - `reply` dropped here while still borrowed 7 | println!("{longest}"); | ------- borrow later used here
The usual fix. Move the owner to an outer scope, or return an owned value instead of a reference.
E0106Missing lifetime specifier
A function returns a reference, but with two inputs the compiler cannot tell which one the output borrows from. It will not guess; you say so with a lifetime name.
error[E0106]: missing lifetime specifier --> src/main.rs:1:30 | 1 | fn pick(a: &str, b: &str) -> &str { | ---- ---- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b` help: consider introducing a named lifetime parameter | 1 | fn pick<'a>(a: &'a str, b: &'a str) -> &'a str { | ++++ ++ ++ ++
The usual fix. Add a lifetime parameter that ties the output to the inputs it really borrows from: fn pick<'a>(a: &'a str, b: &'a str) -> &'a str.
E0515Returned a reference to a local variable
The local is dropped when the function returns, so a reference to it would point at freed memory.
error[E0515]: cannot return value referencing local variable `owned` --> src/main.rs:3:5 | 3 | &owned[..1] | ^-----^^^^^ | || | |`owned` is borrowed here | returns a value referencing data owned by the current function
The usual fix. Return the owned value (String) instead of a reference to it.
E0716A temporary value is dropped while borrowed
The right-hand side built a value that lives only until the end of the statement, and you kept a reference to it.
error[E0716]: temporary value dropped while borrowed --> src/main.rs:2:19 | 2 | let s: &str = String::from("tmp").as_str(); | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | | creates a temporary value which is freed while still in use 3 | println!("{s}"); | - borrow later used here | help: consider using a `let` binding to create a longer lived value | 2 ~ let binding = String::from("tmp"); 3 ~ let s: &str = binding.as_str(); |
The usual fix. Bind the owned value to its own variable first so it lives as long as the reference.
Types and patterns 6
Rust converts nothing behind your back and checks every case.
E0308Mismatched types
Rust never converts between types behind your back. A string where a number was declared, an i32 where an f32 was expected, a missing trailing expression: all this one error.
error[E0308]: mismatched types --> src/main.rs:2:28 | 2 | let temperature: f32 = "0.7"; | --- ^^^^^ expected `f32`, found `&str` | | | expected due to this
The usual fix. Convert explicitly (.parse(), as, .to_string()) or fix the declared type. Read the “expected / found” pair — it names both.
E0063Missing field in a struct literal
Every field of a struct must be given a value when you build it. There are no optional fields — if a value can be absent, its type is Option<T> and you write None.
error[E0063]: missing field `content` in initializer of `ChatMessage` --> src/main.rs:7:13 | 7 | let m = ChatMessage { role: String::from("user") }; | ^^^^^^^^^^^ missing `content`
The usual fix. Add the missing field, or use struct update syntax (..Default::default()).
E0004Non-exhaustive match
A match must cover every possible value. This is the feature that makes adding an enum variant safe: the compiler lists every place you forgot to handle the new case.
error[E0004]: non-exhaustive patterns: `Role::Assistant` not covered --> src/main.rs:8:11 | 8 | match r { | ^ pattern `Role::Assistant` not covered | note: `Role` defined here --> src/main.rs:1:6 | 1 | enum Role { | ^^^^ ... 4 | Assistant, | --------- not covered = note: the matched value is of type `Role` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | 10 ~ Role::User => "user", 11 ~ Role::Assistant => todo!(), |
The usual fix. Add the missing arm, or a deliberate _ catch-all if you truly mean “everything else”.
E0072Recursive type has infinite size
A type that contains itself directly has no finite size. Put the recursion behind a pointer, which has a fixed size.
error[E0072]: recursive type `Plan` has infinite size --> src/main.rs:1:1 | 1 | struct Plan { | ^^^^^^^^^^^ 2 | step: String, 3 | next: Option<Plan>, | ---- recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | 3 | next: Option<Box<Plan>>, | ++++ +
The usual fix. Wrap the recursive field in Box<…>.
E0369Binary operator not supported for this type
Joining two &str with + is not defined — only String + &str is, because the left side must be an owned buffer to extend.
error[E0369]: cannot add `&str` to `&str` --> src/main.rs:2:29 | 2 | let prompt = "system: " + "be brief"; | ---------- ^ ---------- &str | | | | | `+` cannot be used to concatenate two `&str` strings | &str | = note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference | 2 | let prompt = "system: ".to_owned() + "be brief"; | +++++++++++
The usual fix. Use format!, or make the left side an owned String.
E0282Type annotations needed
Nothing in the program pins down what type a value has, so inference cannot finish. Say the type once and it can.
error[E0282]: type annotations needed for `Vec<_>` --> src/main.rs:2:9 | 2 | let embedding = Vec::new(); | ^^^^^^^^^ ---------- type must be known at this point | help: consider giving `embedding` an explicit type, where the type for type parameter `T` is specified | 2 | let embedding: Vec<T> = Vec::new(); | ++++++++
The usual fix. Annotate the binding (Vec<f32>) or use a turbofish (Vec::<f32>::new()).
Traits and closures 5
What a type can do, and which promise a closure is making.
E0277A trait bound is not satisfied
You used a value somewhere that needs a capability — Ord to sort, Display to print, Send to cross threads — and the type does not have it. Also what you see when ? is used in a function that returns ().
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> src/main.rs:2:30 | 1 | fn main() { | --------- this function should return `Result` or `Option` to accept `?` 2 | let n: i32 = "42".parse()?; | ^ cannot use the `?` operator in a function that returns `()` | help: consider adding return type | 1 ~ fn main() -> Result<(), Box<dyn std::error::Error>> { 2 | let n: i32 = "42".parse()?; 3 | println!("{n}"); 4 + Ok(()) |
The usual fix. Read the “the trait … is not implemented for …” line, then implement or derive the trait, change the type, or change what the function returns.
E0046Missing trait item in an impl
The trait promises methods; your impl has to supply every one that has no default body.
error[E0046]: not all trait items implemented, missing: `complete` --> src/main.rs:7:1 | 2 | fn complete(&self, prompt: &str) -> String; | ------------------------------------------- `complete` from trait ... 7 | impl LlmProvider for Echo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `complete` in implementation
The usual fix. Implement each missing method — the error names them.
E0038The trait is not dyn-compatible
You wrote dyn Trait, but the trait has a method the compiler cannot call through a pointer — it returns Self, or is generic. Static dispatch can do it; a vtable cannot.
error[E0038]: the trait `Tool` is not dyn compatible --> src/main.rs:6:29 | 6 | let _tools: Vec<Box<dyn Tool>> = Vec::new(); | ^^^^ `Tool` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> src/main.rs:2:28 | 1 | trait Tool { | ---- this trait is not dyn compatible... 2 | fn duplicate(&self) -> Self; | ^^^^ ...because method `duplicate` references the `Self` type in its return type = help: consider moving `duplicate` to another trait
The usual fix. Remove or where Self: Sized-gate the offending method, or use generics instead of dyn.
E0525Closure is FnOnce but Fn was required
The closure moves something out of its captures, so it can only run once — but the function you passed it to wants to call it repeatedly.
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` --> src/main.rs:8:19 | 8 | let consume = move || drop(prompt); | ^^^^^^^ ------ closure is `FnOnce` because it moves the variable `prompt` out of its environment | | | this closure implements `FnOnce`, not `Fn` 9 | call_twice(consume); | ---------- ------- the requirement to implement `Fn` derives from here | | | required by a bound introduced by this call | note: required by a bound in `call_twice` --> src/main.rs:1:18 | 1 | fn call_twice<F: Fn()>(f: F) { | ^^^^ required by this bound in `call_twice`
The usual fix. Stop consuming the capture (borrow or clone it inside), or accept FnOnce if one call is enough.
E0599No method with that name for this type
The method does not exist on this type — often because it lives on a trait you have not brought into scope, or on a different type (Option vs its contents).
error[E0599]: no method named `append_item` found for struct `Vec<{integer}>` in the current scope --> src/main.rs:3:7 | 3 | v.append_item(4); | ^^^^^^^^^^^ | help: there is a method `append` with a similar name | 3 - v.append_item(4); 3 + v.append(4); |
The usual fix. Check the type with the hover text in your editor; import the trait; or unwrap the Option/Result first.
Threads and async 1
Work that outlives the function that started it must own what it uses.
E0373Closure may outlive the current function
A spawned thread can run after this function returns, so it cannot merely borrow local variables. It has to own them.
error[E0373]: closure may outlive the current function, but it borrows `batch`, which is owned by the current function --> src/main.rs:5:27 | 5 | let h = thread::spawn(|| println!("{}", batch.len())); | ^^ ----- `batch` is borrowed here | | | may outlive borrowed value `batch` | note: function requires argument type to outlive `'static` --> src/main.rs:5:13 | 5 | let h = thread::spawn(|| println!("{}", batch.len())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: to force the closure to take ownership of `batch` (and any other referenced variables), use the `move` keyword | 5 | let h = thread::spawn(move || println!("{}", batch.len())); | ++++
The usual fix. Add move to the closure so it takes ownership of what it uses.
Names and imports 2
The compiler could not find what you named.
E0425Cannot find a value in scope
The name does not exist where you used it: a typo, a missing let, or a variable declared inside a block you have already left.
error[E0425]: cannot find value `modle_name` in this scope --> src/main.rs:3:20 | 3 | println!("{}", modle_name); | ^^^^^^^^^^ | help: a local variable with a similar name exists | 3 - println!("{}", modle_name); 3 + println!("{}", model_name); |
The usual fix. Check the spelling and the scope the name was declared in.
Taught in: 1.3 Printing and comments
E0433Failed to resolve: use of an undeclared type
Standard-library types outside the prelude have to be imported. HashMap is not in scope until you say where it lives.
error[E0433]: cannot find type `HashMap` in this scope --> src/main.rs:2:17 | 2 | let vocab = HashMap::new(); | ^^^^^^^ use of undeclared type `HashMap` | help: consider importing this struct | 1 + use std::collections::HashMap; |
The usual fix. Add use std::collections::HashMap;.
No error matches that. Try a code such as E0382, or a word like “moved” or “lifetime”.