From b591eeca3a2f48be70b09a4866d64ba6c8874b68 Mon Sep 17 00:00:00 2001 From: Raushan Kumar Date: Tue, 7 Apr 2026 12:22:00 +0000 Subject: [PATCH 1/2] tests: add regression test for misleading error when package name is mistyped --- tests/testsuite/package_features.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/testsuite/package_features.rs b/tests/testsuite/package_features.rs index d3f0882a2ef..beb0c0dbf11 100644 --- a/tests/testsuite/package_features.rs +++ b/tests/testsuite/package_features.rs @@ -779,6 +779,32 @@ fn non_member() { .run(); } +#[cargo_test] +fn non_member_typo() { + // -p with a mistyped package name currently shows a misleading error + // without any hint about similar workspace member names. + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar"] + resolver = "2" + "#, + ) + .file("bar/Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("bar/src/lib.rs", "") + .build(); + + p.cargo("build -p barr --all-features") + .with_status(101) + .with_stderr_data(str![[r#" +[ERROR] cannot specify features for packages outside of workspace + +"#]]) + .run(); +} + #[cargo_test] fn resolver1_member_features() { // --features member-name/feature-name with resolver="1" From d4660ffffa35686712795b7562ce1d15ae4fcc7e Mon Sep 17 00:00:00 2001 From: Raushan Kumar Date: Tue, 7 Apr 2026 13:00:37 +0000 Subject: [PATCH 2/2] fix(core): suggest similar member name for mistyped -p with feature flags --- src/cargo/core/workspace.rs | 18 +++++++++++++++--- tests/testsuite/package_features.rs | 20 ++++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index 357381cf822..c3e15daa165 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -47,8 +47,8 @@ use crate::util::errors::{CargoResult, ManifestError}; use crate::util::interning::InternedString; use crate::util::toml::{InheritableFields, read_manifest}; use crate::util::{ - Filesystem, GlobalContext, IntoUrl, context::CargoResolverConfig, context::ConfigRelativePath, - context::IncompatibleRustVersions, + Filesystem, GlobalContext, IntoUrl, closest_msg, context::CargoResolverConfig, + context::ConfigRelativePath, context::IncompatibleRustVersions, }; use cargo_util::paths; @@ -1890,7 +1890,19 @@ impl<'gctx> Workspace<'gctx> { && !cli_features.all_features && cli_features.uses_default_features) { - bail!("cannot specify features for packages outside of workspace"); + let hint = specs + .iter() + .map(|spec| { + closest_msg( + spec.name(), + self.members(), + |m| m.name().as_str(), + "workspace member", + ) + }) + .find(|msg| !msg.is_empty()) + .unwrap_or_default(); + bail!("cannot specify features for packages outside of workspace{hint}"); } // Add all members from the workspace so we can ensure `-p nonmember` // is in the resolve graph. diff --git a/tests/testsuite/package_features.rs b/tests/testsuite/package_features.rs index beb0c0dbf11..6771655e514 100644 --- a/tests/testsuite/package_features.rs +++ b/tests/testsuite/package_features.rs @@ -747,6 +747,8 @@ fn non_member() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `foo` + "#]]) .run(); @@ -755,6 +757,8 @@ fn non_member() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `foo` + "#]]) .run(); @@ -763,6 +767,8 @@ fn non_member() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `foo` + "#]]) .run(); @@ -781,8 +787,8 @@ fn non_member() { #[cargo_test] fn non_member_typo() { - // -p with a mistyped package name currently shows a misleading error - // without any hint about similar workspace member names. + // -p with a mistyped package name shows a helpful error hint + // about similarly named workspace members. let p = project() .file( "Cargo.toml", @@ -801,6 +807,8 @@ fn non_member_typo() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `bar` + "#]]) .run(); } @@ -988,6 +996,8 @@ fn non_member_feature() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `foo` + "#]]) .run(); @@ -1009,6 +1019,8 @@ fn non_member_feature() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `foo` + "#]]) .run(); p.cargo("check -p bar --features bar/jazz") @@ -1016,6 +1028,8 @@ fn non_member_feature() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `foo` + "#]]) .run(); p.cargo("check -p bar --features foo/bar") @@ -1023,6 +1037,8 @@ fn non_member_feature() { .with_stderr_data(str![[r#" [ERROR] cannot specify features for packages outside of workspace +[HELP] a workspace member with a similar name exists: `foo` + "#]]) .run(); }