Skip to content

Rust Error E0616: Field of Struct Is Private

E0616 means: the field you asked for exists, but it’s private to the module where the struct is defined. You’re allowed to hold the struct, just not to reach inside it. It happens to everyone who moves a struct into its own module for the first time, and to everyone who types v.len instead of v.len(). The fix is usually a method call. This page is part of the compiler errors guide.

error[E0616]: field `balance` of struct `Account` is private
--> src/main.rs:16:50
|
16 | println!("{} has {}", account.owner, account.balance); // ❌ private field
| ^^^^^^^ private field

This is the program that produces it:

mod bank {
pub struct Account {
pub owner: String,
balance: u64, // private
}
impl Account {
pub fn new(owner: &str) -> Account {
Account { owner: owner.to_string(), balance: 0 }
}
}
}
fn main() {
let account = bank::Account::new("Ferris");
println!("{} has {}", account.owner, account.balance); // ❌ private field
}

The same error comes in a few flavours:

What you wrote What rustc says Fix
account.balance field `balance` of struct `Account` is private Fix 2 or Fix 3
scores.len on a Vec field `len` of struct `Vec` is private, plus help: a method `len` also exists, call it with parentheses Fix 1
timeout.secs on a Duration field `secs` of struct `Duration` is private Fix 1 (as_secs())
account.balance = 500 the same E0616: writing is blocked too Fix 2

The arrow points at the field name after the dot. account.owner on the same line is fine, because owner is marked pub. balance isn’t, so only code inside mod bank may read or change it.

Notice that Account itself is pub. That’s the part that surprises people: making a struct public does not make its fields public. Each field gets its own pub, or stays private.

Think of a bank. You can walk in, and anyone can see the name on your account. But you can’t walk behind the counter and open the safe to count the money. You ask the teller, and the teller follows the bank’s rules.

In Rust, everything is private by default: functions, modules, and struct fields too (see Modules). Privacy is about modules, not types. Any code inside mod bank can touch balance, and code outside can’t.

The point is to let a struct keep its own rules. Say a bank balance must never go negative. If every part of the program could write account.balance = ..., any of them could break that rule, and you’d have to search the whole codebase to find which one did. If the field is private, only the few methods inside mod bank can change it. Check the rule there, and it holds everywhere. This idea is called encapsulation.

The standard library does the same. A Vec has private fields for its length and its memory buffer. If you could write v.len = 100 on a vector that holds 3 items, reading v[50] would read random memory. Keeping len private is what makes Vec safe to use.

Fix 1: Call the method instead of reading the field

Section titled “Fix 1: Call the method instead of reading the field”

Choose this when the struct comes from the standard library or another crate. You can’t change their code, and they always give you methods for what you’re allowed to see. When rustc says help: a method ... also exists, add the ():

use std::time::Duration;
fn main() {
let scores = vec![10, 20, 30];
println!("{} scores", scores.len());
let timeout = Duration::from_secs(90);
println!("Timeout: {} seconds", timeout.as_secs());
}

Output:

3 scores
Timeout: 90 seconds
▶ Try it Yourself

The method name isn’t always the field name (secs is read with as_secs()). Look at the type’s page on docs.rs, or let your editor list the methods after you type the dot.

Fix 2: Add a getter, and methods that follow the rules

Section titled “Fix 2: Add a getter, and methods that follow the rules”

Choose this when it’s your own struct and the field has a rule to protect. Keep the field private, add a pub fn that returns its value (a getter), and change it only through methods that check the rule:

mod bank {
pub struct Account {
pub owner: String,
balance: i64, // private: only this module can change it
}
impl Account {
pub fn new(owner: &str) -> Account {
Account { owner: owner.to_string(), balance: 0 }
}
// Getter: anyone may read the balance.
pub fn balance(&self) -> i64 {
self.balance
}
pub fn deposit(&mut self, amount: i64) {
if amount > 0 {
self.balance += amount;
}
}
// The rule lives here: the balance never goes below zero.
pub fn withdraw(&mut self, amount: i64) -> Result<(), String> {
if amount > self.balance {
return Err(format!("only {} available", self.balance));
}
self.balance -= amount;
Ok(())
}
}
}
fn main() {
let mut account = bank::Account::new("Ferris");
account.deposit(100);
println!("{} has {}", account.owner, account.balance());
match account.withdraw(500) {
Ok(()) => println!("Withdrew 500"),
Err(e) => println!("Cannot withdraw 500: {e}"),
}
println!("Balance is still {}", account.balance());
}

Output:

Ferris has 100
Cannot withdraw 500: only 100 available
Balance is still 100
▶ Try it Yourself

Rust lets a method and a field share a name, so balance() is the usual name for the getter (not get_balance()). Once the getter exists, rustc even suggests it: help: a method `balance` also exists, call it with parentheses. deposit and withdraw are your setters: they change the field, but only in ways the rules allow. See Structs for more on methods.

Fix 3: Make the field pub when the data is plain

Section titled “Fix 3: Make the field pub when the data is plain”

Choose this when any value is fine and nothing else depends on the field. A point on a grid, a colour, or a settings struct has no rule to protect. Getters there are just extra typing:

mod geometry {
pub struct Point {
pub x: i32,
pub y: i32,
}
}
fn main() {
let mut p = geometry::Point { x: 3, y: 4 };
p.x += 1;
println!("Point at ({}, {})", p.x, p.y);
}

Output:

Point at (4, 4)
▶ Try it Yourself

When only your own code should see the field, write pub(crate) x: i32 (any module in this crate) or pub(super) x: i32 (only the parent module). In a program these behave like pub; in a library they keep the field out of your public API. The E0603 page has a table of all the levels.

Should you just make it pub? Ask: “Could some value of this field, or a change to it alone, make the struct wrong?” A negative balance, a len that doesn’t match the data, a total that no longer equals the sum of the items: keep those private and use Fix 2. If the answer is “no, any value is fine”, pub is the honest choice.

len on a Vec. You wrote scores.len and got field `len` of struct `Vec` is private. That’s because Vec really has a private field called len. The fix is scores.len(). Funny detail: name.len on a String gives a different error, E0615 (attempted to take value of method), because String has no field with that name. Same fix.

Setting a field from outside. account.balance = 500; gives the same E0616. Writing is also blocked. Don’t make the field pub just to set it; add a method like deposit that does the change and checks it.

After moving a struct into its own module or file. Code in main.rs used user.email for months. Then you moved User into src/user.rs and every field access broke. Fields that were fine before are now private to mod user. Add pub to the fields that are plain data, and getters for the rest.

Tests. A #[cfg(test)] mod tests block inside the same file is a child module, so it can read private fields. Tests in the tests/ folder are outside your crate and can only use the pub API, like any other user.

  • E0603: function `x` is private. The same idea for functions, structs and modules.
  • E0451: the same private field, but while creating the struct with Account { ... }.
  • E0624: method `x` is private. The method (or new) needs pub too.
  • E0609: no field `x` on type `T` . The field doesn’t exist at all (often a typo).
  • E0615: attempted to take value of method. You wrote x.len and meant x.len().
  • All compiler errors: the full list of error pages.

Quick check

1. pub struct Account { balance: u64 } is in mod bank. Can main read account.balance?

2. You get `field len of struct Vec is private`. What's the fix?

3. A Score struct has a points field that must stay between 0 and 100. What's the best design?

Score: 0 / 3