Skip to content

fix(path): clarify error message when path dependency has wrong package#16927

Open
raushan728 wants to merge 2 commits intorust-lang:masterfrom
raushan728:fix-15296
Open

fix(path): clarify error message when path dependency has wrong package#16927
raushan728 wants to merge 2 commits intorust-lang:masterfrom
raushan728:fix-15296

Conversation

@raushan728
Copy link
Copy Markdown
Contributor

@raushan728 raushan728 commented Apr 22, 2026

View all comments

Fixes #15296

When a path dependency specifies a package name that doesn't match what's
found at that path, Cargo now shows helpful hints about what packages exist
nearby instead of the confusing "location searched" message.

@rustbot rustbot added A-dependency-resolution Area: dependency resolution and the resolver S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 22, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 22, 2026

r? @epage

rustbot has assigned @epage.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ehuss, @epage, @weihanglo
  • @ehuss, @epage, @weihanglo expanded to ehuss, epage, weihanglo
  • Random selection from ehuss, epage, weihanglo

Copy link
Copy Markdown
Contributor

@epage epage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/cargo/core/resolver/errors.rs Outdated
Comment thread src/cargo/core/resolver/errors.rs Outdated
Comment thread src/cargo/core/resolver/errors.rs Outdated
Comment thread src/cargo/core/resolver/errors.rs Outdated
Comment thread src/cargo/sources/path.rs Outdated
pub fn load(&self) -> CargoResult<()> {
let mut package = self.package.borrow_mut();
if package.is_none() {
if !self.path.join("Cargo.toml").exists() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this added?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was an earlier attempt to handle missing Cargo.toml - reverted because it was too broad and broke existing tests. Now i use typed error detection in registry.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From #16927 (comment)

Note for reviewers: The change in registry.rs is needed to handle case 2 and case 3 (where bar/ exists as a directory but has no Cargo.toml). Without it the IO error fires before the resolver reaches activation_error_path_hints. The suppression is guarded by three conditions: path source, typed ManifestError with NotFound, and has_nearby_manifests confirming subdirectory packages exist.

Comment thread src/cargo/core/resolver/errors.rs Outdated
if s.is_empty() {
s.push('.');
}
if !s.ends_with('/') {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use file_name() to show the actual directory name (e.g. foo/) instead of ./ when the path equals the parent root

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That isn't a complete sentence, making it harder to follow what you mean. I don't see how a file_name() (which?) even fits into this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When path == parent_root, strip_prefix returns an empty string. In that case we fall back to path.file_name() to show the directory name (e.g. foo/) rather than an empty or confusing path

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file_name() doesn't make sense here. We should probably be using pathdiff or using an absolute path

The original point I raised was actually about always appending / since that isn't something users are likely to do

Comment thread src/cargo/core/resolver/errors.rs Outdated
Comment thread src/cargo/core/resolver/errors.rs Outdated
Comment thread tests/testsuite/path.rs Outdated
@rustbot rustbot added the A-registries Area: registries label Apr 23, 2026
@raushan728
Copy link
Copy Markdown
Contributor Author

Note for reviewers: The change in registry.rs is needed to handle
case 2 and case 3 (where bar/ exists as a directory but has no
Cargo.toml). Without it the IO error fires before the resolver
reaches activation_error_path_hints. The suppression is guarded by
three conditions: path source, typed ManifestError with NotFound,
and has_nearby_manifests confirming subdirectory packages exist.

@raushan728 raushan728 requested a review from epage April 23, 2026 12:47
Comment thread src/cargo/core/resolver/errors.rs
Comment thread src/cargo/core/resolver/errors.rs
Comment thread src/cargo/core/resolver/errors.rs Outdated
Comment on lines +734 to +743
let res = source.query(dep, kind, f).await;
if let Err(e) = &res {
if dep.source_id().is_path()
&& crate::core::resolver::errors::is_manifest_not_found(e)
&& has_nearby_manifests(dep)
{
return Ok(());
}
}
res.with_context(|| format!("unable to update {}", source.source_id()))
Copy link
Copy Markdown
Contributor

@epage epage Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has really ballooned in complexity, including the idea of "catching" specific errors.

View changes since the review

Copy link
Copy Markdown
Contributor Author

@raushan728 raushan728 Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The registry.rs change was needed because without it, the IO error fires before the resolver reaches the diagnostic code for cases 2/3.

Is there a cleaner way you'd suggest to intercept this early failure so we can still provide helpful hints for those cases? Happy to rework the approach if you have a better path in mind.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From #16927 (comment)

Regarding registry.rs - every alternative approach I tried but they broke existing tests. This is the cleanest I could find while keeping everything green.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have strong reservations about this approach and would need to understand why there is no other way, rather than being told that.

@raushan728 raushan728 force-pushed the fix-15296 branch 2 times, most recently from d4eb6f0 to d5f8d89 Compare April 24, 2026 06:09
…ge (rust-lang#15296)

When a path dependency points to a directory with a different package,
show which package exists there and where the correct one can be found.
@raushan728

This comment was marked as duplicate.

@raushan728 raushan728 requested a review from epage April 26, 2026 14:48
Comment on lines +390 to +400
let _ = writeln!(
&mut msg,
"no matching package named `{}` found at `{}`",
dep.package_name(),
rel_path(&path),
);
let _ = write!(
&mut msg,
"required by {}",
describe_path_in_context(resolver_ctx, &parent.package_id()),
);
Copy link
Copy Markdown
Contributor

@epage epage Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does is_handled_custom_path_error till exist?

On the surface, it looks like we use it to move the location searched: message into the line before it but it isn't clear why we feel that complexity is worth it.

View changes since the review

/// Checks if an error is a "manifest not found" error (Cargo.toml missing).
/// This is used to allow the resolver to continue and provide helpful hints
/// for path dependencies instead of failing immediately with a load error.
pub fn is_manifest_not_found(err: &anyhow::Error) -> bool {
Copy link
Copy Markdown
Contributor

@epage epage Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we keep this, why is it here when only used in the Source?

View changes since the review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-dependency-resolution Area: dependency resolution and the resolver A-registries Area: registries S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve error message when wrong package found in a path dependency

3 participants