How to fix Rust E0425 cannot find value in scope

Fix Rust E0425 by defining the missing variable, importing it with `use`, or marking it `pub` to make it visible in the current scope.

The name isn't there

You just refactored your code. You moved the calculate_score function into a utils module to keep your main file tidy. You hit save. The compiler immediately yells E0425: cannot find value 'calculate_score' in this scope. You stare at the screen. The function is right there, three lines up in the other file. Why does Rust think it doesn't exist?

This error is the compiler's way of saying it cannot resolve the name you typed at the location where you typed it. Rust enforces strict boundaries around where names are visible. It doesn't guess. It doesn't search the whole project for a similar name and hope you meant that one. It checks the rules of scope and visibility, finds a violation, and stops.

Scope and visibility

Rust organizes code into nested containers. The outermost container is the crate. Inside the crate are modules. Inside modules are functions. Inside functions are blocks marked by curly braces. Each container defines a scope. A scope is the region of code where a name is valid.

Think of your code like a set of locked rooms. A variable defined in one room doesn't magically appear in another. The compiler checks the room you are currently standing in. If it can't find the name on the list of things allowed in this room, it throws E0425.

Visibility is a separate layer. Even if a name exists in a parent room, it might be hidden behind a curtain. Items in modules are private by default. Private items are invisible to code outside their module. You need two things to use a name from elsewhere: the name must be visible (marked pub or equivalent), and the name must be in scope (imported or accessed via a path).

Scope is a hard boundary. The compiler doesn't care if the variable is "right there". If it's not in the current scope, it doesn't exist.

Minimal example

Variables enter scope when they are defined and leave scope when the block ends. Using a name outside its valid range triggers E0425.

/// Demonstrates E0425 caused by scope boundaries.
///
/// Variables defined in a nested block are not visible outside that block.
fn main() {
    // This block creates a new scope.
    {
        let secret = 99; // `secret` is born here.
        println!("Inside: {}", secret); // Valid: `secret` is in scope.
    } // `secret` dies here. The scope ends.

    // E0425: cannot find value `secret` in this scope.
    // The compiler has no record of `secret` in this outer block.
    // println!("Outside: {}", secret);
}

The compiler reads your code top-to-bottom within a scope. It also tracks nesting. When it sees a name, it looks in the current block. If not found, it looks in the parent block. It climbs up the nesting until it finds the name or hits the top. If it hits the top without finding the name, you get E0425.

Define variables before you use them. The compiler reads your code in order.

How the compiler looks up names

When you compile, Rust builds a symbol table. This table maps every name to its definition and its scope. The lookup process is mechanical.

  1. The compiler encounters an identifier, like x or calculate_score.
  2. It checks the current scope. Is there a let x, a fn x, or a use x here?
  3. If yes, it uses that definition.
  4. If no, it checks the parent scope.
  5. It repeats step 4 until it finds the name or reaches the crate root.
  6. If the name is never found, the compiler emits E0425.

The error message includes the name it couldn't find and the scope it was checking. This tells you exactly where the lookup failed. If the error points to a variable, check if you defined it. If it points to a function, check if you imported it.

The compiler helps by suggesting similar names in some cases. If you type prnitln, the error might suggest println. Always check the suggestion. Typos are the most common cause of E0425.

Real-world module structure

In real projects, E0425 usually comes from module boundaries. You split code into files. Each file is a module. Items in modules are private by default. You must explicitly expose items and import them to share them.

/// Realistic scenario: Module visibility and imports.
///
/// This file represents `src/lib.rs`.
/// Modules encapsulate code. Items are private by default.
/// You must explicitly expose and import items to share them.

mod kitchen {
    /// Prepares the meal.
    ///
    /// Marked `pub` so other modules can see this function.
    /// Without `pub`, this function is invisible outside `kitchen`.
    pub fn cook() {
        println!("Cooking...");
    }
}

// Bring `cook` into the current scope.
// This creates a local alias so you can call `cook()` directly.
// Without this `use`, `cook` is not in scope here.
use kitchen::cook;

/// Serves the meal to the customer.
pub fn serve() {
    // `cook` is now in scope via the `use` statement.
    cook();
}

Visibility and scope are two locks. You need both keys to open the door. Adding pub makes the item visible to other modules, but it doesn't bring the name into your current scope. You still need a use statement or the full path kitchen::cook().

Convention aside: Prefer pub(crate) over bare pub. It exposes the item to the whole crate but hides it from external users. This keeps your public API clean and prevents accidental exposure.

mod kitchen {
    /// Prepares the meal.
    ///
    /// `pub(crate)` makes this visible within the crate,
    /// but hidden from crates that depend on this one.
    pub(crate) fn cook() {
        println!("Cooking...");
    }
}

Common traps

E0425 has a few patterns that trip up developers. Recognizing the pattern speeds up the fix.

Typos and casing. Rust matches names exactly. String is a type. string is not. Vec is a type. vec is a macro. Mixing them up triggers E0425. Check your spelling. Check your capitalization. The compiler rejects undefined names with E0425. It doesn't guess. If you type prnitln, Rust reports E0425.

Missing use for traits. Sometimes you see a method in the documentation, but calling it causes E0425. This happens when the method belongs to a trait, and the trait isn't in scope. Trait methods are only available when the trait is imported.

/// Demonstrates E0425 with trait methods.
///
/// The `Read` trait defines the `read` method.
/// If `Read` is not in scope, you cannot call `read`.
fn process_data() {
    let mut buffer = Vec::new();

    // E0425: cannot find value `Read` in this scope.
    // The trait `Read` is not imported.
    // Read::read(&mut buffer);

    // Fix: Import the trait.
    // use std::io::Read;
    // Now `Read::read` works, or you can call `.read()` on types that implement `Read`.
}

Glob imports. Using use std::io::* imports everything from io. This can cause E0425 if you expect an item that isn't exported by the glob, or if there's a name collision. Glob imports are discouraged in libraries because they make dependencies unclear. Stick to explicit imports.

Path vs value. E0425 is for values. If you have a module path error, you might get E0433 instead. E0433 means the path couldn't be resolved. E0425 means the name couldn't be found. If you get E0425, check the name. If you get E0433, check the path.

Trust the error message. It tells you exactly what name it couldn't find. Fix the name, or bring it in.

Decision matrix

Pick the fix that matches the cause. A typo needs a keystroke. A module needs a use.

Fix typos when the name is misspelled or has wrong casing. Rust matches names exactly. Correct the spelling to match the definition.

Define the variable when you forgot to create it. Add let x = ... before the usage. Ensure the definition is in the same scope or a parent scope.

Move the definition up when the variable is trapped in a nested block. Scopes end at the closing brace. Move the let binding outside the block, or pass the value as an argument.

Add pub and use when the item lives in another module. Visibility and scope are separate steps. Mark the item pub (or pub(crate)) in the source module, then add a use statement in the destination module.

Import the trait when you're calling a method that exists on the type but isn't found. Methods from traits require the trait to be in scope. Add use TraitName; to enable the methods.

Use the full path when you don't want to pollute the namespace with a use statement. std::fs::read_to_string works without importing. This is useful for rarely used items.

Where to go next