Fix E0090: Unresolved Import in Rust

Rust beginner Linux macOS Windows WebAssembly

1. Symptoms

When Rust encounters error E0090, the compiler produces output that clearly identifies which import statement cannot be resolved. The error message includes the exact line number and the problematic path that the compiler failed to find.

error[E0090]: unresolved import `module::submodule`
 --> src/main.rs:3:5
  |
3 | use module::submodule;
  |     ^^^^^^^^^^^^^^^^ could not find `submodule` in `module`

In more complex scenarios involving external crates, the error might indicate that a crate itself cannot be found:

error[E0090]: unresolved import `external_crate::some_module`
 --> src/lib.rs:5:12
  |
5 | use external_crate::some_module;
  |            ^^^^^^^^^^^ could not find `some_module` in `external_crate` which is not a direct dependency

The compiler may also suggest alternative paths or modules that exist when the exact path cannot be resolved. When the import refers to a non-existent item within an otherwise valid module structure, the error points specifically to the missing item name.

Nested import errors produce messages that indicate exactly where the chain breaks:

error[E0090]: unresolved import `crate_name::path::to::missing_item`
 --> src/mod.rs:2:5
  |
2 | use crate_name::path::to::missing_item;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not find `missing_item` in `to`

2. Root Cause

Error E0090 emerges from Rust’s module resolution system when the compiler attempts to locate an item specified in a use statement but cannot map that path to any actual declaration in the codebase. The resolution process follows a strict hierarchy: first checking the current crate, then external dependencies, and finally the standard library. When any segment of this path fails to resolve, the compiler halts and reports E0090.

The underlying causes fall into several distinct categories. Typos in import paths represent the most frequent trigger, where a simple spelling mistake prevents the compiler from matching the intended item. Rust’s path resolution is case-sensitive, meaning HttpRequest and HTTPRequest would be treated as entirely different paths.

Missing modules occur when you reference a module that hasn’t been declared in the current crate’s module tree. In Rust, modules must be explicitly declared using the mod keyword before they can be used in import statements. A file existing on disk is insufficient if it’s not registered within the module hierarchy.

Incorrect external dependency references happen when a crate hasn’t been added to Cargo.toml. The compiler can only resolve imports from crates that are listed in the manifest file under [dependencies] or [dev-dependencies]. Version mismatches can also cause this error if an item existed in an older version but was removed or renamed in the current version.

Privacy violations manifest as E0090 when attempting to import items that aren’t marked as public. Rust defaults to private visibility, and attempting to use non-public items from outside their defining module triggers a resolution failure. The item exists but cannot be accessed through the specified path from the given location.

Renamed or removed items after refactoring frequently produce E0090 when old import statements aren’t updated to match the new structure. The compiler faithfully attempts to resolve paths that no longer exist in the expected locations.

3. Step-by-Step Fix

Resolving E0090 requires identifying exactly where your import path diverges from reality. Follow this systematic approach to diagnose and fix the issue.

Step 1: Examine the compiler’s exact error location

The error message pinpoints the problematic line in your source file. Open that file and locate the use statement on the indicated line number. Copy the exact path being imported for reference.

Step 2: Verify the module or crate exists

For external crates, open your Cargo.toml file and confirm the crate is listed under [dependencies]. If missing, add it with the appropriate version specification:

Before:

[dependencies]

After:

[dependencies]
serde = "1.0"

Step 3: Check the module hierarchy

For internal modules, ensure the module containing your target item has been declared. In the parent module or file, verify a corresponding mod declaration exists:

Before:

// src/main.rs
use my_module::utils;  // E0090 if utils not declared

After:

// src/main.rs
mod my_module;  // Declare the module first
use my_module::utils;

Step 4: Verify the item exists and is public

Inspect the actual module file to confirm the item you’re importing has been defined and marked as public:

Before:

// src/my_module/utils.rs
struct helper_function();  // Private by default

After:

// src/my_module/utils.rs
pub struct helper_function();  // Explicitly public

Step 5: Correct the import path

Fix typos, adjust case sensitivity, and ensure the path matches the actual structure:

Before:

use std::collections::HashMap;  // May work
use std::collections::hashmap;  // E0090: wrong case and name

After:

use std::collections::HashMap;  // Correct casing and name

Step 6: Handle renamed items

When items have been renamed through re-exports, use the correct path or alias:

Before:

use crate::old_module::removed_function;  // E0090

After:

use crate::new_module::renamed_function;  // Correct new location

Step 7: Update for renamed crates

When a dependency has been renamed on crates.io but internally uses a different crate name:

Before:

[dependencies]
winapi = "0.3"  // Actually imported as 'windows' in code

After:

[dependencies]
windows = { version = "0.3", package = "winapi" }

4. Verification

After applying your fix, recompile the project to confirm the error has been resolved. Run the standard build command appropriate to your setup:

cargo build

A successful build produces output without any E0090 errors:

Compiling my_project v0.1.0 (/path/to/project)
    Finished dev [unoptimized + debuginfo] target(s) in 0.5s

Execute your project’s tests to ensure the fix hasn’t introduced regressions:

cargo test

All tests should pass, confirming that the imported items function correctly within your codebase. If you’re working with a library, verify that the public API exports are accessible as intended by testing imports from a dependent crate or binary target.

For complex module hierarchies, add targeted tests that specifically exercise the imported functionality:

#[cfg(test)]
mod import_tests {
    use crate::module::submodule::target_item;
    
    #[test]
    fn test_imported_item_exists() {
        // Verify the item can be accessed and used
        let result = target_item::new();
        assert!(result.is_valid());
    }
}

Run this specific test to confirm the import chain functions correctly:

cargo test import_tests

5. Common Pitfalls

Several recurring mistakes cause E0090 to persist even after apparent fixes. Understanding these traps helps avoid wasted debugging time.

Assuming files exist without declarations: Creating a new file like src/network.rs doesn’t automatically make it a module. You must explicitly declare it in a parent module with mod network; before importing anything from it. The filesystem structure and Rust’s module tree are independent until explicitly linked.

Forgetting pub visibility: Rust’s privacy rules are enforced at the module boundary. An item defined as struct Internal cannot be imported from outside its module, even if the path is technically correct. Always audit the visibility of items you’re trying to import.

Case sensitivity in paths: While Rust follows Rust conventions (CamelCase for types, snake_case for functions and variables), import paths are case-sensitive. io::Read and io::read resolve to entirely different targets.

Confusing use with mod: The use statement brings items into scope from already-existing modules. It cannot create modules or declare their existence. If you’re receiving E0090 on a path you believe should work, double-check that all intermediate modules exist and have been declared.

Outdated dependencies: When a dependency updates and removes or renames an item, your imports break. Check the crate’s changelog or documentation when updating versions. The cargo outdated tool can help track dependency versions.

Nested path imports with missing intermediate segments: When writing use outer::middle::inner::item, every segment of that path must exist and be accessible. Partial paths that resolve some segments but not others produce E0090 pointing to the first unresolvable segment.

Circular dependencies: Rust prevents circular module dependencies, but when they occur, the compiler may report E0090 for items in the cycle. Restructure your module hierarchy to eliminate cycles.

E0432: Unresolved import: This error specifically indicates that a use statement cannot find the target module or item. While E0090 covers similar ground, E0432 sometimes provides more context about why the resolution failed, such as indicating that an external crate wasn’t found.

E0433: Failed to resolve: This error occurs when the compiler cannot find the start of an import path, typically because the crate or module specified at the beginning of the path doesn’t exist. It differs from E0090 in that E0433 addresses the root of the path rather than an intermediate segment.

E0580: Unresolved import path with extern crate: This error specifically involves extern crate declarations and occurs when the specified crate cannot be found in the dependency graph. It commonly appears when the crate name in extern crate doesn’t match the package name in Cargo.toml.

Understanding the distinction between these errors helps pinpoint exactly which part of your import system requires correction. E0090 typically resolves to one of these more specific errors when additional context is available from the compiler’s analysis passes.