Skip to content

Rust Error E0609: No Field X on Type T

E0609 means: you wrote value.something, but the type of value has no field called something. Most of the time it’s a typo, or the value isn’t quite the type you think it is (an Option<User> instead of a User, for example). The error message tells you the exact type Rust sees, and that’s usually all you need to fix it. (This page is part of Rust compiler errors explained.)

error[E0609]: no field `emial` on type `User`
--> src/main.rs:12:25
|
12 | println!("{}", user.emial); // ❌ typo: the field is `email`
| ^^^^^ unknown field
|
help: a field with a similar name exists
|
12 - println!("{}", user.emial); // ❌ typo: the field is `email`
12 + println!("{}", user.email); // ❌ typo: the field is `email`
|

This is the program that produces it:

struct User {
name: String,
email: String,
}
fn main() {
let user = User {
name: String::from("Ferris"),
email: String::from("[email protected]"),
};
println!("{}", user.name);
println!("{}", user.emial); // ❌ typo: the field is `email`
}

The headline has two parts, and both matter:

  • no field `emial`: the name after the dot that Rust couldn’t find.
  • on type `User`: the type Rust thinks user has.

So first check the name, then check the type. If the type in the message is not the struct you expected, for example Option<User>, &Option<User>, Vec<User> or &T, the name is fine and the problem is that you need to get the struct out first.

It’s like asking a shop for “the blue one on the second shelf” when you’re standing in the wrong shop. The request is fine, you’re just in the wrong place.

In Rust, every struct’s fields are fixed when you write the struct. The compiler knows the full list and checks every .field at compile time. There’s no “look it up at runtime and get undefined” like in JavaScript, or AttributeError like in Python: a wrong field name never makes it into your program. See Structs.

Wrapper types like Option<T> and Result<T, E> are separate types: your struct sits inside them, but they don’t have its fields. Rust doesn’t reach through them for you, because the value might not be there at all. You have to say what happens when it’s missing. See Option.

Generic code follows the same strict rule. In fn greet<T>(x: &T), T could be any type, including i32 or bool, which have no fields. Rust checks a generic function once for every possible T, so it only lets you use what your trait bounds promise. And traits can only promise methods, not fields. See Generics and Traits.

Choose this when the type in the message is the struct you expected. Look for the help: a field with a similar name exists line; rustc usually knows exactly which field you meant:

struct User {
name: String,
email: String,
}
fn main() {
let user = User {
name: String::from("Ferris"),
email: String::from("[email protected]"),
};
println!("{}", user.name);
println!("{}", user.email); // ✅ the real field name
}

Output:

▶ Try it Yourself

If there’s no hint, jump to the struct definition (in most editors: Ctrl+click or F12 on the type) and copy the name from there. Field names are case-sensitive: userName and user_name are different fields.

Fix 2: Get the struct out of the Option first

Section titled “Fix 2: Get the struct out of the Option first”

Choose this when the message says the type is Option<User>, Option<&User> or &Option<User>. This happens all the time with functions that might not find something, and with methods like .first(), .last(), .get() and .find():

error[E0609]: no field `name` on type `Option<User>`
--> src/main.rs:11:25
|
11 | println!("{}", user.name);
| ^^^^ unknown field
|
help: one of the expressions' fields has a field of the same name
|
11 | println!("{}", user.unwrap().name);
| +++++++++

The .unwrap() hint compiles, but it crashes the program when the value is None. Better: decide what should happen in both cases, with if let, match, or map plus a default:

struct User {
name: String,
}
fn find_user(id: u32) -> Option<User> {
if id == 1 {
Some(User { name: String::from("Ferris") })
} else {
None
}
}
fn main() {
// if let: only run the code when there is a User
if let Some(user) = find_user(1) {
println!("Found: {}", user.name);
}
// match: handle both cases
match find_user(2) {
Some(user) => println!("Found: {}", user.name),
None => println!("No user with id 2"),
}
// map + unwrap_or: take a field, or use a default
let users = vec![User { name: String::from("Ada") }];
let first_name = users.first().map(|u| u.name.as_str()).unwrap_or("nobody");
println!("First user: {first_name}");
}

Output:

Found: Ferris
No user with id 2
First user: Ada
▶ Try it Yourself

The same patterns work on a reference to an Option. If maybe_user is a &Option<User>, write if let Some(user) = maybe_user and user is a &User. (For &Option<User> rustc gives no hint at all, so it’s worth remembering.) Inside a function that returns Option, let user = find_user(1)?; also works. See Handling an Option with match and if let.

Choose this when the type is a tuple struct, like struct Point(i32, i32);. Its fields have no names, only positions, so p.x gives no field `x` on type `Point` (with the hint p.0). Use the position, or unpack it into named variables. If you want names, make it a struct with named fields:

struct Point(i32, i32); // tuple struct: fields are .0 and .1
struct Size {
width: u32, // named fields: use .width and .height
height: u32,
}
fn main() {
let p = Point(3, 4);
println!("x = {}, y = {}", p.0, p.1);
let Point(x, y) = p; // or unpack it into named variables
println!("squared distance = {}", x * x + y * y);
let screen = Size { width: 1920, height: 1080 };
println!("{}x{}", screen.width, screen.height);
}

Output:

x = 3, y = 4
squared distance = 25
1920x1080
▶ Try it Yourself

Plain tuples work the same way. pair.2 on a two-element tuple gives E0609 with the note available fields are: `0`, `1`. See Accessing elements by position.

Fix 4: Use a trait method instead of a field on a generic T

Section titled “Fix 4: Use a trait method instead of a field on a generic T”

Choose this when the message says on type `&T` (or T), with the label type parameter 'T' declared here. Code like this fails, even if every type you pass in has a name field:

fn greet<T>(animal: &T) {
println!("Hello, {}!", animal.name); // ❌ no field `name` on type `&T`
}

Traits can’t require fields, but they can require a getter method. Define a small trait, implement it for each type, and add it as a bound on T:

trait Named {
fn name(&self) -> &str;
}
struct Dog {
name: String,
}
struct Robot {
model: String,
}
impl Named for Dog {
fn name(&self) -> &str {
&self.name
}
}
impl Named for Robot {
fn name(&self) -> &str {
&self.model // the field doesn't even need the same name
}
}
fn greet<T: Named>(thing: &T) {
println!("Hello, {}!", thing.name()); // a method call, not a field
}
fn main() {
greet(&Dog { name: String::from("Rex") });
greet(&Robot { model: String::from("R2-D2") });
}

Output:

Hello, Rex!
Hello, R2-D2!
▶ Try it Yourself

If the function only ever works with one type, you don’t need a generic at all: write fn greet(animal: &Dog) and animal.name works. See Traits as function parameters.

A method without (). Writing word.len or cart.total (where total is a method) is close to E0609, but rustc gives a different code: E0615, “attempted to take value of method”, with the hint “use parentheses to call the method”. On a Vec, scores.len gives E0616, “field len of struct Vec is private”, because Vec really has a hidden field with that name. Same fix for both: word.len(), scores.len(), cart.total(). And "hello".length is plain E0609 on &str: in Rust it’s called len(). See Strings.

A Vec instead of one item. dogs.name on a Vec<Dog> gives no field `name` on type `Vec<Dog>`. A list has no name, each item does. Fix: pick one with dogs[0].name, or loop with for dog in &dogs { println!("{}", dog.name); }. See Vectors.

A Result instead of the value. load_config().port gives no field `port` on type `Result<Config, String>`, with the same .unwrap() hint. Fix: let config = load_config()?; inside a function that returns Result, or a match. See The ? operator.

A field on a number. age.value on a u32 is a different code again: E0610, “u32 is a primitive type and therefore doesn’t have fields”. Numbers, bool and char have no fields at all; you probably meant a struct variable.

Quick check

1. The error says there is no field name on type Option<User>. What does it tell you?

2. How do you read the first field of struct Meters(f64); from a value m?

3. In fn show<T>(x: &T), how can you read a name from every T?

Score: 0 / 3