Rust Error E0603: Function, Struct or Module Is Private
E0603 is good news in disguise: Rust found the function, struct or module you asked for. It just isn’t allowed to hand it to you, because the item is private. Everything in a Rust module is private until you say otherwise, so this error shows up the first time almost everyone splits code into modules. The fix is usually one word, pub. This page is part of the compiler errors guide.
The error message
Section titled “The error message”error[E0603]: function `apply_discount` is private --> src/main.rs:8:26 |8 | let total = billing::apply_discount(200); // ❌ private | ^^^^^^^^^^^^^^ private function |note: the function `apply_discount` is defined here --> src/main.rs:2:5 |2 | fn apply_discount(price: u32) -> u32 { // no `pub` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^This is the program that produces it:
mod billing { fn apply_discount(price: u32) -> u32 { // no `pub` price * 90 / 100 }}
fn main() { let total = billing::apply_discount(200); // ❌ private println!("Total: {total}");}The first line names the kind of item, so the same error comes in a few flavours:
| What the first line says | What usually went wrong | Fix |
|---|---|---|
function `apply_discount` is private |
the fn has no pub |
Fix 1 or Fix 2 |
struct `Order` is private |
the struct has no pub |
Fix 1 |
module `prices` is private |
a mod on the path has no pub |
Fix 1 or Fix 3 |
function import `price_of` is private |
you reached an item through a plain use inside another module |
Fix 3 |
tuple struct constructor `Percent` is private |
the struct is pub, but its fields are not |
Fix 4 |
What it means
Section titled “What it means”Read the two arrows. The first one (line 8) is where you use the item. The note: arrow (line 2) is where the item is defined. Rust is saying: “I see apply_discount over there, but it was never marked as shared, so code outside billing can’t call it.”
The file doesn’t matter. If billing lives in src/billing.rs, you get the same error, and the note: simply points at src/billing.rs:1:1 instead.
Think of an office building. Each module is a room with a door. A private item is a tool that stays in its room: people inside the room (and in smaller rooms inside it) can use it, but nobody from the hallway can. pub puts the tool on a shelf in the hallway.
Why Rust does this
Section titled “Why Rust does this”Rust makes everything private by default: functions, structs, struct fields, modules and even use imports. You opt in to sharing with pub. The Modules lesson shows this from the start.
The reason is safety for future you. Whatever is pub becomes a promise: other code may depend on it, so changing it can break that code. Private items are free to change, rename or delete, and the compiler guarantees nobody outside relies on them. Small helper functions stay helpers, and a struct can protect its own rules (like “a balance is never negative”) because nobody else can touch its fields directly.
One more detail: privacy is checked for every step of a path. shop::prices::price_of only works if prices is visible to you and price_of is visible to you. A pub fn inside a private module is still out of reach.
How to fix it
Section titled “How to fix it”Fix 1: Add pub to the item (and to every module on the path)
Section titled “Fix 1: Add pub to the item (and to every module on the path)”Choose this when the item is meant to be used from outside its module. This is the right fix most of the time:
mod billing { pub fn apply_discount(price: u32) -> u32 { price * 90 / 100 }}
fn main() { let total = billing::apply_discount(200); println!("Total: {total}");}Output:
Total: 180If the error says module `prices` is private, the missing pub is on the module: write pub mod prices { ... }. rustc also tells you this case with a second label, function `price_of` is not publicly re-exported. With a separate file, the pub goes on the declaration line: pub mod prices;.
For a struct, pub struct Order makes the type public, but each field still needs its own pub if outside code should read or set it. More on that in Fix 4.
Fix 2: Use pub(crate) or pub(super) for “only my code”
Section titled “Fix 2: Use pub(crate) or pub(super) for “only my code””Choose this when the item should be shared, but not with the whole world. pub has a few levels, from smallest to biggest:
| You write | Who can use the item |
|---|---|
| nothing (private) | its own module, and the modules inside it |
pub(super) |
also the parent module |
pub(crate) |
any code in this crate |
pub |
everyone, including other crates that depend on yours |
In a program (a binary), pub(crate) and pub behave almost the same. The difference matters in a library: pub(crate) lets your modules share a helper without making it part of the library’s public API.
mod shop { // Any code in this crate may call this. pub(crate) fn store_name() -> &'static str { "Ferris Fruits" }
pub mod receipt { // Only the parent module, `shop`, may call this helper. pub(super) fn line(item: &str, price: u32) -> String { format!("{item}: {price}") } }
pub fn print_receipt(items: &[(&str, u32)]) { println!("== {} ==", store_name()); for (item, price) in items { println!("{}", receipt::line(item, *price)); } }}
fn main() { println!("Welcome to {}", shop::store_name()); shop::print_receipt(&[("apple", 3), ("pear", 5)]); // shop::receipt::line("apple", 3); // ❌ E0603: `line` is only for `shop`}Output:
Welcome to Ferris Fruits== Ferris Fruits ==apple: 3pear: 5Remove the // in front of the last line and you get function `line` is private, even though it says pub(super). main is not the parent of receipt, so the door stays closed.
Fix 3: Re-export with pub use
Section titled “Fix 3: Re-export with pub use”Choose this when the inner module is an internal detail, but one item inside it should be easy to reach. Keep the module private and put the item on a shorter, public path:
mod shop { mod prices { // stays private: how prices are stored is shop's business pub fn price_of(item: &str) -> u32 { if item == "apple" { 3 } else { 5 } } }
pub use prices::price_of; // now reachable as shop::price_of}
fn main() { println!("Apples cost {}", shop::price_of("apple")); println!("Pears cost {}", shop::price_of("pear"));}Output:
Apples cost 3Pears cost 5This is also the fix for function import `price_of` is private. A plain use prices::price_of; inside shop is a shortcut for shop only; like everything else, a use is private. pub use turns the shortcut into a public door. Big crates do this all the time, so you can write serde::Serialize without knowing which inner module it lives in.
Fix 4: Add a pub fn new instead of making fields public
Section titled “Fix 4: Add a pub fn new instead of making fields public”Choose this when the error is about a struct’s fields or its constructor. Here the struct is pub, but its field isn’t:
mod billing { pub struct Percent(u8);}
fn main() { let discount = billing::Percent(150); // ❌ private constructor}error[E0603]: tuple struct constructor `Percent` is private --> src/main.rs:6:29 |2 | pub struct Percent(u8); | -- a constructor is private if any of the fields is private...6 | let discount = billing::Percent(150); // ❌ private constructor | ^^^^^^^ private tuple struct constructor |help: consider making the field publicly accessible |2 | pub struct Percent(pub u8); | +++rustc suggests pub u8, and for a plain data type that’s fine. But look at the value: 150 percent! Often the private field is the point. The module wants to check the value before a Percent exists. Give it a public constructor that does the checking:
mod billing { pub struct Percent(u8);
impl Percent { pub fn new(value: u8) -> Option<Percent> { if value <= 100 { Some(Percent(value)) } else { None } }
pub fn apply(&self, price: u32) -> u32 { price * (100 - self.0 as u32) / 100 } }}
fn main() { let ten = billing::Percent::new(10).unwrap(); println!("200 with 10% off: {}", ten.apply(200)); println!("Is 150% allowed? {}", billing::Percent::new(150).is_some());}Output:
200 with 10% off: 180Is 150% allowed? falseNow every Percent in the whole program is guaranteed to be between 0 and 100, and apply can never underflow. Remember that new itself needs pub too; a private method gives a different error, E0624 (associated function `new` is private). See Structs for more on constructors.
Where you’ll usually see it
Section titled “Where you’ll usually see it”A package with both main.rs and lib.rs. They are two separate crates, and main.rs uses the library from the outside. If lib.rs says mod inventory;, then use shop::inventory::count_items; in main.rs fails:
error[E0603]: module `inventory` is private --> src/main.rs:1:11 |1 | use shop::inventory::count_items; | ^^^^^^^^^ private moduleFix: write pub mod inventory; in lib.rs and pub fn count_items in the module. Watch out: pub(crate) is not enough here. To the library, main.rs is another crate, so a pub(crate) fn still gives function `count_items` is private. See Cargo and crates.
Private struct fields. These get their own error codes. Creating a struct with a private field gives E0451, and reading one gives E0616:
error[E0451]: field `balance` of struct `Account` is privateerror[E0616]: field `balance` of struct `Account` is privateFix: the same choice as Fix 4. Add pub to the field if anyone may change it, or keep it private and add pub fn new(...) plus a getter like pub fn balance(&self) -> u64.
A function you found in a crate’s source code. You read a crate on GitHub, found the perfect helper, and get E0603 when you call it. If the crate’s authors didn’t make it pub, you can’t use it, and they may change it any time. Look for a public way to do the same thing on the crate’s page at docs.rs; only pub items appear there.
Related errors
Section titled “Related errors”- E0432:
unresolved import. The item wasn’t found at all. With E0603 it was found, but it’s private. - E0433:
failed to resolve, a path in your code that leads nowhere. - E0451 and E0616: a struct field is private (creating the struct, or reading the field).
- E0624: a method or associated function (like
new) is private. - All compiler errors: the full list of error pages.
Quick check
Section titled “Quick check”Quick check
1. mod shop { mod prices { pub fn price_of() {} } } and main calls shop::prices::price_of(). Which error do you get?
2. A helper in src/lib.rs is marked pub(crate). Can src/main.rs in the same package call it?
3. A pub struct Email(String); keeps its field private on purpose. What's the friendly way to let other modules create one?
Score: 0 / 3
Read more
Section titled “Read more”- E0603 — Rust error codes index: the official explanation with a minimal example.
- Paths for Referring to an Item in the Module Tree — The Rust Book: exposing paths with
pub, and howpubworks on structs and enums. - Bringing Paths into Scope with the
useKeyword — The Rust Book: re-exporting names withpub use. - Visibility — Rust by Example:
pub,pub(crate),pub(super)andpub(in path)in one runnable example. - Visibility and privacy — The Rust Reference: the exact rules, for when you want the full picture.