Fix E0670: Rust Uniform Path Syntax Error
Rust E0670 is a compiler error that occurs when code written for Rust 2015 edition uses the deprecated :: prefix syntax for accessing external crates. This error emerged as part of the significant module system improvements introduced in Rust 2018 edition, which introduced uniform path syntax across all crate types. The compiler is enforcing the new, more consistent path resolution rules that eliminate the need for the :: prefix when referring to external crates or standard library items.
1. Symptoms
When E0670 is triggered, you will see an error message similar to the following in your compiler output:
error[E0670]: `::` is not permitted in paths before Rust 2018 edition
--> src/main.rs:3:5
|
3 | ::std::collections::HashMap;
| ^^ help: remove the `::` prefix
|
= note: for an overview of what changed in Rust 2018, see
https://doc.rust-lang.org/nightly/edition-guide/rust-2018/module-system/index.html
The error appears at compile time and prevents the binary from being built. The caret symbol (^^) in the error message points directly to the problematic :: prefix characters. In more complex scenarios involving nested module imports or macro invocations, you might encounter additional spans pointing to multiple instances of this deprecated syntax:
error[E0670]: `::` is not permitted in paths before Rust 2018 edition
--> src/lib.rs:5:12
|
5 | let map = ::std::collections::HashMap::new();
| ^^ help: remove the `::` prefix
If your Cargo.toml specifies edition = "2015" explicitly or relies on the default (which is 2015 if no edition is specified), the compiler will flag any occurrence of the old-style :: prefix as an error. The error message specifically mentions Rust 2018 edition changes, indicating that the fix involves either updating the code syntax or migrating to a newer edition.
2. Root Cause
The root cause of E0670 lies in the fundamental changes to Rust’s module and path resolution system that shipped with the 2018 edition. Before Rust 2018, external crates were required to be prefixed with :: in use statements and expressions to distinguish them from local modules. For example, in Rust 2015 code, you would write use ::std::io::Read; to explicitly indicate that std is an external crate and not a local module named std in your project hierarchy.
Rust 2018 introduced “uniform paths,” which eliminated this distinction. In Rust 2018 and later editions, the compiler resolves std, core, and alloc directly without requiring the :: prefix. External crates referenced in Cargo.toml are also resolved uniformly through the normal path resolution algorithm. The :: prefix was therefore deprecated and subsequently became a hard error in the 2018 edition and beyond.
When the Rust compiler encounters :: in a path, it treats this as the old-style explicit external crate reference syntax. If your crate is compiled with Rust 2018 edition or later, this syntax is not valid because the uniform path system makes the :: prefix unnecessary and ambiguous. The compiler specifically checks for this pattern during the parsing phase and emits E0670 before attempting any further semantic analysis.
This error is particularly common when code written for Rust 2015 is being compiled with a newer Rust compiler that defaults to 2018 edition or later, or when developers copy code examples from older documentation, tutorials, or Stack Overflow answers without recognizing the deprecated syntax. It also appears in generated code or scaffolding from older tooling that hasn’t been updated to use the new edition’s conventions.
3. Step-by-Step Fix
The fix for E0670 involves removing the :: prefix from affected paths. There are two primary approaches: updating the code syntax directly or migrating your crate to Rust 2018 edition or later. The recommended approach depends on your project’s circumstances and compatibility requirements.
Option A: Remove the :: Prefix (Quick Fix)
Identify all occurrences of :: prefix in your code and remove them. The prefix can appear in use statements, expressions, and type annotations.
Before:
// src/main.rs
extern crate serde;
use ::serde::{Deserialize, Serialize};
use ::std::collections::HashMap;
use ::std::io::Read;
fn main() {
let mut map = ::std::collections::HashMap::new();
let reader = ::std::io::BufReader::new(file);
}
After:
// src/main.rs
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::io::Read;
fn main() {
let mut map = std::collections::HashMap::new();
let reader = std::io::BufReader::new(file);
}
Option B: Migrate to Rust 2018 Edition
Update your Cargo.toml to specify a newer edition, which also allows removing the now-deprecated extern crate declarations.
Before:
# Cargo.toml
[package]
name = "my-project"
version = "0.1.0"
edition = "2015"
[dependencies]
serde = "1.0"
After:
# Cargo.toml
[package]
name = "my-project"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = "1.0"
With Rust 2018 or later, you can also remove extern crate declarations entirely since the compiler handles crate imports automatically:
Before:
extern crate serde;
extern crate std;
fn process(data: String) {
use std::io::Write;
// ...
}
After:
use serde::Serialize;
fn process(data: String) {
// std crate is automatically in scope
// ...
}
Option C: Handling Edge Cases with core and alloc
When working with no_std environments or specific scenarios involving the core and alloc crates, similar adjustments are needed:
Before:
#![no_std]
extern crate alloc;
use ::core::fmt;
use ::alloc::string::String;
use ::alloc::vec::Vec;
After:
#![no_std]
extern crate alloc;
use core::fmt;
use alloc::string::String;
use alloc::vec::Vec;
4. Verification
After applying the fix, verify that the error is resolved by recompiling your crate. Run the following command to check for successful compilation:
cargo build
A successful build produces output without any E0670 errors:
Compiling my-project v0.1.0 (/path/to/my-project)
Finished dev [unoptimized + debuginfo] target(s) in 0.52s
For projects with multiple crates or workspace configurations, verify all crates compile correctly:
cargo build --all
cargo test --all
If you chose to migrate to a newer edition, confirm that the Cargo.toml reflects the change and that there are no other edition-related issues:
cargo check
rustc --version
You should also run your test suite to ensure that the syntax changes haven’t introduced any behavioral regressions:
cargo test
Pay special attention to any #[macro_use] declarations or procedural macros that might still reference the old-style paths. If your project uses build scripts (build.rs), verify that they also don’t contain the deprecated syntax.
5. Common Pitfalls
One of the most frequent mistakes developers make when encountering E0670 is attempting to add configuration options to suppress the error rather than fixing the underlying syntax. There is no lint attribute or compiler flag that allows you to use the :: prefix syntax in Rust 2018 and later editions—it is a hard error by design, not a warning that can be silenced.
Another common pitfall involves conditional compilation with #[cfg] attributes. Code that branches between Rust 2015 and 2018 editions might use the :: prefix inside #[cfg] blocks that are only compiled under certain conditions. Always verify that conditional compilation branches are also updated, as they will trigger the error when those conditions are met.
Developers migrating large codebases sometimes overlook that :: can appear in macro invocations and attribute parameters. For example, #[serde(rename = "::std::fmt")] or string literals containing paths like "::module::item" should be reviewed and updated. String literals containing the :: prefix are generally safe since they represent literal string values rather than paths, but code that parses or generates paths should be examined carefully.
When using procedural macros or derive macros from third-party crates, ensure that those crates also support your target edition. Some older macro crates may generate code containing the deprecated syntax when used with newer editions. In such cases, updating the macro crate to a compatible version or finding an alternative crate is necessary.
Finally, be cautious when using code generation tools, scaffolding generators, or templates that were created for Rust 2015. These tools may inject the old-style syntax into newly generated files. Always review generated code for deprecated patterns before attempting to compile.
6. Related Errors
E0463: “extern crate declaration cannot have cfg attribute” — This error often appears alongside E0670 when migrating from Rust 2015 to later editions. The extern crate declarations themselves are deprecated in Rust 2018, and any #[cfg] attributes on them become invalid. Migrating to the newer edition’s import system resolves both issues.
E0433: “failed to resolve” — This error can occur when the :: prefix removal is done incompletely, leaving paths that reference non-existent modules or crates. After removing the prefix, verify that all module paths are still valid and that any renamed crates (using as in the old extern crate syntax) are properly imported under their new names.
E0763: “extern crate declaration cannot appear in the root of the compilation unit” — This error specifically relates to the removal of extern crate declarations in Rust 2018 and later. It appears when explicit extern crate statements remain in code compiled with a newer edition. The solution is to remove these declarations entirely, as crates are now implicitly available through their crate names.