rust-lang/cargo · error
cannot mix `proc-macro` crate type with others
Error message
cannot mix `proc-macro` crate type with others
What it means
When `crate-type` contains `proc-macro`, it must be the sole entry. A proc-macro crate must export only `#[proc_macro_derive]`/`#[proc_macro_attribute]` items at the crate root and cannot coexist with other crate types. The match arm at targets.rs:257-259 emits a warning suggesting `proc-macro = true`, then bails if `kinds.len() > 1`.
Solutions
- Replace `crate-type = ["proc-macro", ...]` with the boolean `proc-macro = true` (the recommended form).
- If you must use `crate-type`, list only `["proc-macro"]`.
- Move non-macro code into a separate companion crate.
Example fix
# before [lib] crate-type = ["proc-macro", "rlib"] # after [lib] proc-macro = true
Defensive patterns
Strategy: validation
Validate before calling
fn proc_macro_mixed(crate_types: &[String]) -> bool {
crate_types.iter().any(|t| t == "proc-macro") && crate_types.len() > 1
}
// prefer `[lib] proc-macro = true` over explicit crate-type Prevention
- Use `proc-macro = true` instead of `crate-type = ["proc-macro"]`.
- Never list `proc-macro` alongside other crate types.
- Keep proc-macro crates focused solely on macros.
When it happens
Trigger: Cargo.toml has `[lib] crate-type = ["proc-macro", "rlib"]` or any list where `proc-macro` appears alongside another type. The `if kinds.len() > 1` check inside the proc-macro arm fires.
Common situations: Trying to ship a proc-macro and a normal library from the same crate. Migrating from `proc-macro = true` to explicit crate-type and leaving extra entries. IDE/template scaffolding that pre-fills multiple crate types.
Related errors
- can't find library ` `, rename file to `src/lib.rs` or…
- cannot compile ` ` as the target ` ` does not support any…
- cannot specify both `metabuild` and `build`
- found build scripts with duplicate file stems, but all…
- found duplicate name , but all targets must have a unique…
AI-assisted analysis of rust-lang/cargo@eb98b54bc9 (2026-08-11).
Data as JSON: /api/errors/cc9e26621beeef43.
Report an issue: GitHub.
Appendix: source
Thrown at src/workspace/parser/targets.rs:258
// A plugin requires exporting plugin_registrar so a crate cannot be
// both at once.
let crate_types = match (lib.crate_types(), lib.proc_macro()) {
(Some(kinds), _)
if kinds.contains(&CrateType::Dylib.as_str().to_owned())
&& kinds.contains(&CrateType::Cdylib.as_str().to_owned()) =>
{
anyhow::bail!(format!(
"library `{}` cannot set the crate type of both `dylib` and `cdylib`",
name_or_panic(lib)
));
}
(Some(kinds), _) if kinds.contains(&"proc-macro".to_string()) => {
warnings.push(format!(
"library `{}` should only specify `proc-macro = true` instead of setting `crate-type`",
name_or_panic(lib)
));
if kinds.len() > 1 {
anyhow::bail!("cannot mix `proc-macro` crate type with others");
}
vec![CrateType::ProcMacro]
}
(Some(kinds), _) => kinds.iter().map(|s| s.into()).collect(),
(None, Some(true)) => vec![CrateType::ProcMacro],
(None, _) => vec![CrateType::Lib],
};
let mut target = Target::lib_target(name_or_panic(lib), crate_types, path, edition);
configure(lib, &mut target, TARGET_KIND_HUMAN_LIB, warnings)?;
target.set_name_inferred(original_lib.map_or(true, |v| v.name.is_none()));
Ok(Some(target))
}
#[tracing::instrument(skip_all)]
pub fn normalize_bins(
toml_bins: Option<&Vec<TomlBinTarget>>,
package_root: &Path,View on GitHub (pinned to eb98b54bc9)