Question
When I run the following command to install Racer:
cargo install racer
Cargo fails while compiling the scoped-tls dependency with this error:
error[E0554]: #![feature] may not be used on the stable release channel
--> .../scoped-tls-0.1.2/src/lib.rs:47:34
|
47 | #![cfg_attr(feature = "nightly", feature(macro_vis_matcher))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: #![feature] may not be used on the stable release channel
--> .../scoped-tls-0.1.2/src/lib.rs:48:34
|
48 | #![cfg_attr(feature = "nightly", feature(allow_internal_unstable))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I am using Rust 1.30.0, Cargo 1.30.0, and rustup 1.14.0 on openSUSE Tumbleweed. Why is Cargo trying to use #![feature(...)] on the stable channel, and what should I check or change to install the package correctly?
Short Answer
Rust has separate stable, beta, and nightly toolchains. Error E0554 means that the crate being compiled enabled an unstable compiler feature, but Cargo invoked the stable compiler. You will learn how Cargo chooses a toolchain, how dependency features can trigger nightly-only code, and how to diagnose and safely resolve this kind of installation failure.
Concept
Rust deliberately keeps experimental language and compiler capabilities behind feature gates. A crate enables one with a crate attribute such as:
#![feature(some_unstable_feature)]
Only a nightly Rust compiler accepts that attribute. The stable compiler rejects it with E0554, even if the attribute appears inside a dependency rather than in your own code.
In the reported output, scoped-tls contains:
#![cfg_attr(feature = "nightly", feature(macro_vis_matcher))]
cfg_attr means “apply this attribute only when a condition is true.” Therefore, this line only becomes a #![feature(...)] declaration when the dependency's nightly Cargo feature is enabled.
That gives two important clues:
- Cargo is compiling with the stable toolchain.
- Some package or feature selection caused
scoped-tlsto compile its nightly-specific code path.
This matters because applications commonly have many transitive dependencies: your project depends on a package, which depends on another package, and so on. A build failure can originate several layers away from the package you explicitly installed.
Mental Model
Think of Rust toolchains as different editions of a workshop.
- Stable is the public workshop: its tools are tested and approved for everyday work.
- Nightly is the experimental workshop: it includes prototype tools that may change or disappear.
A #![feature(...)] attribute is like requesting a prototype tool. Stable sees that request and says, “That tool is not available in this workshop.”
Cargo is the project manager that gathers every supplier (dependency). Even if your own project never requests a prototype tool, one supplier can request it. The whole build then needs a compatible workshop, or the dependency configuration must be changed.
Syntax and Examples
A crate attribute applies to the entire crate and is usually placed at the top of src/lib.rs or src/main.rs.
#![feature(example_feature)]
This is rejected by stable Rust and accepted only by a compatible nightly compiler.
A conditional crate attribute avoids enabling the feature unless a Cargo feature is selected:
#![cfg_attr(feature = "nightly", feature(example_feature))]
pub fn message() -> &'static str {
"Hello"
}
With the nightly feature disabled, the compiler effectively sees only:
pub fn message() -> &'static str {
"Hello"
}
With the nightly feature enabled, it effectively sees:
#![feature(example_feature)]
pub fn message() -> &'static str {
"Hello"
}
Cargo features are declared in Cargo.toml:
[features]
nightly = []
They are enabled by a dependent package, a command-line option, or another feature that includes them. Features are additive: once a feature is enabled anywhere in the dependency graph, it remains enabled for that package build.
Step by Step Execution
Consider this dependency configuration:
# App Cargo.toml
[dependencies]
helper = { version = "1.0", features = ["nightly"] }
# helper Cargo.toml
[features]
nightly = ["scoped-tls/nightly"]
[dependencies]
scoped-tls = "0.1"
// scoped-tls/src/lib.rs
#![cfg_attr(feature = "nightly", feature(macro_vis_matcher))]
When you run cargo build on stable Rust, the sequence is:
- Cargo reads the app manifest and sees that
helperneeds itsnightlyfeature. - The
helperfeature enablesscoped-tls/nightly. - Cargo compiles
scoped-tlswith itsnightlyfeature enabled. cfg_attrturns into#![feature(macro_vis_matcher)].- Stable
rustcencounters#![feature(...)]. - The compiler stops with
error[E0554].
The error location is in scoped-tls, but the cause may be the top-level package version, its manifest, or another dependency that enabled the feature.
Real World Use Cases
Toolchains and feature gating appear in several practical situations:
- Command-line tools:
cargo install tool-namecompiles the tool and all of its dependencies using the selected Rust toolchain. - Libraries with optional optimizations: a crate may offer an experimental nightly implementation behind a
nightlyfeature while keeping a stable implementation by default. - CI pipelines: a project may test stable Rust for supported users and nightly Rust to experiment with upcoming language changes.
- Developer tooling: editors, linters, language servers, and code-analysis tools can have older releases that were built against a particular Rust ecosystem version.
- Reproducible builds: a lockfile or explicit version can ensure that a build uses known-compatible dependency releases rather than a newly resolved version.
Real Codebase Usage
In real Rust projects, developers generally keep nightly requirements explicit rather than accidentally enabling them.
Check the active toolchain
rustup show active-toolchain
rustc --version
cargo --version
If a project intentionally needs nightly, select it for one command:
cargo +nightly build
Or pin the project toolchain with rust-toolchain.toml:
[toolchain]
channel = "nightly"
Inspect dependency feature selection
For a Cargo project, inspect the resolved graph and enabled features:
cargo tree -e features
To focus on a particular dependency:
cargo tree -e features -i scoped-tls
The inverse (-i) view helps identify which package enabled a dependency or its feature.
Prefer stable-compatible versions
For a package installation failure, first update the Rust toolchain and retry a current compatible package release:
rustup update stable
cargo +stable install racer
If the package documents that a particular release needs nightly, use nightly deliberately:
rustup toolchain install nightly
cargo +nightly install racer
Do not edit files in Cargo's registry cache as a fix. Cargo can download them again, and changing the source does not explain why the incompatible feature was selected.
Common Mistakes
Assuming the error is caused by your own source code
The path in the error can point into Cargo's registry:
~/.cargo/registry/src/.../scoped-tls-0.1.2/src/lib.rs
That means a dependency failed to compile. Inspect the package version and dependency features rather than searching only your application files.
Adding #![feature(...)] to a stable project
This does not solve the problem:
#![feature(macro_vis_matcher)]
On stable, it produces the same error. The solution is to use a stable-compatible dependency configuration or deliberately compile using nightly.
Treating cfg_attr as harmless
This code is conditional, not always safe on stable:
#![cfg_attr(feature = "nightly", feature(example_feature))]
If the nightly feature is enabled, stable compilation fails. Check which features are active.
Installing nightly globally without understanding why
rustup default nightly
This can make unrelated projects use nightly too. Prefer a one-command override (cargo +nightly ...) or a repository-local rust-toolchain.toml when nightly is actually required.
Relying on a very old Rust release
The versions in the question, Rust 1.30.0 and Cargo 1.30.0, are historical. Older compilers may be incompatible with newer package releases, dependency metadata, or build assumptions. Update stable first before diagnosing a modern installation issue.
Editing downloaded registry code
Changing ~/.cargo/registry/src/... is temporary and can introduce an untested build. Fix the selected package version, feature set, or toolchain instead.
Comparisons
| Choice | What it contains | Best use | #![feature(...)] allowed? |
|---|---|---|---|
| Stable | Tested, released Rust features | Most applications, libraries, and tools | No |
| Beta | Next stable release candidate | Compatibility testing before release | No |
| Nightly | Experimental, changing Rust features | Explicit experimentation or nightly-only projects | Yes |
| Mechanism | Purpose | Example |
|---|---|---|
| Rust feature gate | Enables an unstable compiler capability | #![feature(name)] |
| Cargo feature | Selects optional crate code or dependencies | features = ["serde"] |
cfg_attr | Applies an attribute only under a condition | cfg_attr(feature = "nightly", feature(name)) |
Cargo features and Rust feature gates are different. A Cargo feature named nightly is only a package-defined switch; it does not automatically switch the compiler to the nightly toolchain.
Cheat Sheet
# See the selected toolchain
rustup show active-toolchain
# Update stable Rust
rustup update stable
# Install and use nightly for one command
rustup toolchain install nightly
cargo +nightly build
# Install a Cargo package explicitly with stable
cargo +stable install package-name
# Inspect resolved dependency features in a project
cargo tree -e features
cargo tree -e features -i dependency-name
# Read Rust's explanation for this compiler error
rustc --explain E0554
E0554means stable or beta Rust encountered#![feature(...)].cfg_attr(feature = "x", attribute)appliesattributeonly when Cargo featurexis enabled.- Dependency features are additive across the graph.
- Prefer updating Rust and using a stable-compatible release first.
- Use
+nightlyonly when the package truly requires nightly. - Do not manually modify Cargo registry sources.
FAQ
What does Rust error E0554 mean?
It means the active compiler is stable or beta, but compiled source contains a #![feature(...)] attribute. Those attributes require nightly Rust.
Why does the error appear inside a dependency instead of my project?
Cargo compiles all transitive dependencies. A dependency can enable an unstable feature even when your own source code does not use one.
Does a Cargo feature called nightly automatically select the nightly compiler?
No. Cargo features select package code. Toolchain selection is separate and is controlled by rustup, a toolchain file, or commands such as cargo +nightly build.
Should I use nightly to fix E0554?
Only if the package or project intentionally requires nightly. First update stable Rust and check whether a newer or different package version supports stable.
How can I see which dependency enabled a feature?
In a Cargo project, run cargo tree -e features. Use cargo tree -e features -i package-name to see packages that depend on a named package.
Why might an old Cargo installation fail when installing a tool?
Older Rust and Cargo versions may not satisfy the tool's minimum supported Rust version or may resolve an old dependency set with known compatibility problems. Updating through rustup is usually the first check.
Can I remove the nightly feature from a dependency file in the Cargo registry?
You can alter local files temporarily, but it is not a reliable solution. The change can be overwritten and may break the dependency. Correct the manifest, version selection, or toolchain instead.
Mini Project
Description
Create a small Rust library that offers a normal stable implementation and an optional nightly-only implementation. The project demonstrates the difference between a Cargo feature and selecting a Rust toolchain, without requiring any external dependency.
Goal
Build the project on stable Rust by default, then observe why enabling its nightly feature requires a nightly compiler.
Requirements
Create a library crate named toolchain_demo.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.