← Debugging Guides

阅读中文版本

Rust proc-macro crate not available — Macro Import Fails

Fix "proc-macro crate not available" and unresolved derive errors by separating the proc-macro crate and importing derives through the facade.

advanceddebuggingrustproc-macrocargo

Symptoms

  • error: proc-macro crates cannot export items other than macros
  • error[E0433]: failed to resolve: could not find `X` in `Y`
  • Deriving a macro fails only in downstream crates

Possible causes

  • A proc-macro crate tries to export regular items or is used as a normal dependency
  • The derive macro is defined in a crate without proc-macro = true
  • Macros are re-exported without the required pub use or a facade crate

Diagnosis steps

Verify the crate type

grep -n "proc-macro" Cargo.toml

Interpretation

A derive-defining crate must declare proc-macro = true under [lib]; otherwise it cannot define derives.

Reproduce the resolve error

cargo build 2>&1 | grep -E "proc-macro|E0433" | head

Interpretation

The resolution failure names the crate and item, showing whether the export or the dependency is wrong.

Root cause

A proc-macro crate compiles to a compiler plugin and may only export macros. If it also exports traits or functions, the build fails; consumers must import the macro through the crate that legally exports it.

Fix

Split the crate so the proc-macro crate only defines macros, move shared items to a normal library crate, and re-export derives through a facade so users import one crate.

Risk note

Changing the crate type can break existing import paths; provide a facade and deprecate the old path gradually.

Verify the fix

cargo build succeeds and a downstream crate derives the macro; cargo doc shows the macro exported from the facade.

Symptoms

This debugging guide addresses “Rust proc-macro crate not available — Macro Import Fails”. Start from the symptoms, follow the ordered diagnostics, and confirm each hypothesis before moving on; the fix and verification steps then close the loop.

Observed symptoms include:

  • error: proc-macro crates cannot export items other than macros
  • error[E0433]: failed to resolve: could not find X in Y
  • Deriving a macro fails only in downstream crates

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Verify the crate type

grep -n "proc-macro" Cargo.toml

A derive-defining crate must declare proc-macro = true under [lib]; otherwise it cannot define derives.

Step 2: Reproduce the resolve error

cargo build 2>&1 | grep -E "proc-macro|E0433" | head

The resolution failure names the crate and item, showing whether the export or the dependency is wrong.

Likely contributors, in order of frequency:

  • A proc-macro crate tries to export regular items or is used as a normal dependency
  • The derive macro is defined in a crate without proc-macro = true
  • Macros are re-exported without the required pub use or a facade crate

Root Cause

A proc-macro crate compiles to a compiler plugin and may only export macros. If it also exports traits or functions, the build fails; consumers must import the macro through the crate that legally exports it.

The Fix

Split the crate so the proc-macro crate only defines macros, move shared items to a normal library crate, and re-export derives through a facade so users import one crate.

Watch out: Changing the crate type can break existing import paths; provide a facade and deprecate the old path gradually.

# Cargo.toml of the proc-macro crate
[lib]
proc-macro = true

[dependencies]
syn = "2"
quote = "1"

# Facade crate re-exports the derive so users import one path
# lib.rs
pub use my_derive::MyTrait;

Verify and Prevent

cargo build succeeds and a downstream crate derives the macro; cargo doc shows the macro exported from the facade.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.