RFA-461 · Case file with fixtures · Case 433 of 694 · Compiler evidence
A Rust Trait Impl Requires the Trait to Be in Scope
Trait impl headers resolve a real trait path in the current module. Verify spelling, imports, re-exports, cfg features, and crate ownership; prefer an explicit path when similarly named traits exist.
- Reviewed
- Rust
- Rust 1.98.1, edition 2024
- Targets
- all Rust targets
- Profiles
- dev, release, test
Direct answer
What this Rust failure means
- Why it happens
- Trait identities are resolved through module scope rather than inferred structurally from method bodies, and the intended declaration or import is absent here.
- First discriminating check
- Identify the owning crate and public trait path, then verify module imports, feature cfg, version, and orphan-rule eligibility before implementing it.
I wrote impl Encodable for Packet without declaring or importing an Encodable trait. Rust returned E0405 because the trait path is not in scope.
The failing fixture looks close to E0404, but the distinction helps: E0405 cannot resolve the trait at all, while E0404 resolves a name that is not a trait.
An impl header participates in normal name resolution
The trait name is not inferred from method shapes. Rust does not search dependencies for any trait called Encodable, and it does not create an implicit interface from the implementation block.
The E0405 explanation asks me to check spelling, declaration, and imports. I begin by identifying the crate and module that owns the intended contract.
This prevents an auto-import from selecting a same-named trait with different semantics.
Declare a local trait only when I own the contract
The repaired fixture declares a small local Encodable trait and implements its required method for Packet.
In an application, that may be the intended design. In integration code, the trait more often comes from a serialization or protocol crate and should be imported from that crate rather than recreated locally.
Two same-shaped traits remain different identities. Defining a replacement will not satisfy generic code bounded by the external one.
Explicit paths can be the clearest repair
I can write:
impl wire::Encodable for Packet { /* ... */ }
The implementation Reference gives the trait impl form. A full path in the header identifies which contract participates in coherence and which documentation defines the obligations.
I may still import associated helper types separately, but I prefer clarity at the impl boundary.
Parent-module imports are not inherited
An item imported into a parent module is not automatically visible by its short name inside a child module. The child can use super::Encodable, add use super::Encodable, or import the original public path.
This often appears when one file becomes a nested module during refactoring. Sibling files compile because they contain their own imports, while the moved impl loses its local scope.
I treat imports as module-local dependencies, not project-global declarations.
Feature flags can remove the trait or re-export
The trait itself or a public re-export may be behind a Cargo feature or target cfg. Rust-analyzer may use a different feature set from CI, making the name appear available in the editor.
I check cargo tree -e features, the defining crate documentation for the active version, and conditional attributes near the export. The repair should align feature activation with the intended capability rather than duplicate conditional declarations.
The evidence fixture avoids Cargo complexity, but production diagnosis cannot.
Method lookup and impl resolution are related but different
Calling an extension method often requires bringing its trait into scope. Writing a trait impl also needs the trait path resolved. However, importing a trait for method lookup does not grant permission to implement it under Rust's orphan rules.
After E0405 is fixed, E0117 may reveal that both the trait and target type are external. I then use a local wrapper or another supported integration point.
Name visibility is only the first contract.
Re-exports define a library's intended surface
A library may expose crate::Encodable while defining it deep under traits::encoding. Downstream code should usually use the public re-export. It is more stable than reaching into internal modules that may later become private.
The use-declaration Reference explains how aliases enter scope. I inspect current documentation rather than copying an old import from a search result.
My E0405 checklist
- Is the trait name spelled correctly for the pinned crate version?
- Which crate and module own the intended trait?
- Is an explicit public path clearer than a short import?
- Did code move into a child module with a new scope?
- Does a feature or target cfg hide the export?
- Am I about to define a different local trait accidentally?
- Will orphan or required-item errors appear after resolution?
- Does editor configuration match the failing build?
The core principle is that a trait implementation names a specific contract, not a structurally guessed interface. I resolve that identity deliberately through the current module and dependency configuration before writing the implementation body.