Skip to content

Fix Non-actionable error messages #15879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

ojuschugh1
Copy link
Contributor

@ojuschugh1 ojuschugh1 commented Aug 22, 2025

What does this PR try to resolve?

This PR fixes issue #15754 where workspace publish failures provided non-actionable error messages. Previously, when publishing a workspace failed (due to rate limiting or other errors), users only saw generic errors like [ERROR] failed to publish to registry without knowing which package failed or what packages remained to be published.

How to test and review this PR?

Testing: Run cargo test workspace_publish_rate_limit_error to see the improved behavior, then cargo test publish to ensure all tests pass.

Review:

  • Commit 1: Adds test demonstrating current problematic behavior
  • Commit 2: Implements fix and updates test to expect improved output

The fix transforms error messages from generic failed to publish to registry to actionable failed to publish 'package_a' v0.1.0; the following crates have not been published yet: package_b v0.1.0, package_c v0.1.0. This improvement applies consistently across all publish error scenarios, giving users clear information about what went wrong and what remains to be done.

@rustbot rustbot added A-interacts-with-crates.io Area: interaction with registries Command-publish labels Aug 22, 2025
@@ -2461,7 +2461,7 @@ fn api_other_error() {
[PACKAGING] foo v0.0.1 ([ROOT]/foo)
[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
[UPLOADING] foo v0.0.1 ([ROOT]/foo)
[ERROR] failed to publish to registry at http://127.0.0.1:[..]/
[ERROR] failed to publish `foo` v0.0.1 to registry at http://127.0.0.1:[..]/
Copy link
Contributor

Choose a reason for hiding this comment

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

Like in #15765, could you split adding the package name to the error in a commit before adding the unpublished packages?

Comment on lines 686 to 701
if let Some(context) = workspace_context {
format!(
"failed to publish `{}` v{} to registry at {}; {}",
pkg.name(),
pkg.version(),
registry.host(),
context
)
} else {
format!(
"failed to publish `{}` v{} to registry at {}",
pkg.name(),
pkg.version(),
registry.host()
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

but we do for a lot of errors is include the separator for optional context in that context and use an empty string instead of None, so we don't need a conditional like this but always include the context.

@@ -4507,7 +4507,7 @@ fn workspace_publish_rate_limit_error() {
[COMPILING] package_c v0.1.0 ([ROOT]/foo/target/package/package_c-0.1.0)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[UPLOADING] package_a v0.1.0 ([ROOT]/foo/package_a)
[ERROR] failed to publish to registry at http://127.0.0.1:[..]/
[ERROR] failed to publish `package_a` v0.1.0 to registry at http://127.0.0.1:[..]/; the following crates have not been published yet: package_b v0.1.0, package_c v0.1.0
Copy link
Contributor

Choose a reason for hiding this comment

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

In #15765, the additional packages were on a separate line

[ERROR] failed to publish package 'a' to registry at http://127.0.0.1:[..]/

Remaining packages to publish: b v0.1.0 and c v0.1.0

Likely what this should look like is

[ERROR] failed to publish `package_a` v0.1.0 to registry at http://127.0.0.1:[..]/

note: the following crates have not been published yet:
  package_b v0.1.0
  package_c v0.1.0

@@ -210,7 +212,7 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
// `b`, and we uploaded `a` and `b` but only confirmed `a`, then on
// the following pass through the outer loop nothing will be ready for
// upload.
for pkg_id in plan.take_ready() {
for pkg_id in plan.take_ready().into_iter() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this change needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The change from for pkg_id in plan.take_ready() to for pkg_id in plan.take_ready().into_iter() was needed because of a Rust type inference issue.

The take_ready() method returns a BTreeSet<PackageId>, and Rust couldn't automatically determine which iterator implementation to use (there are multiple: IntoIterator, Iter, IterMut). By explicitly calling .into_iter(), we tell Rust to use the consuming iterator, which is what we want since take_ready() takes ownership of the set.

This makes the code more explicit and avoids ambiguity in type inference.

Copy link
Contributor

Choose a reason for hiding this comment

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

I just did a checkout of your branch and deleted the into_iter and it built just fine. In fact, for is defined as calling IntoIterator::into_iter

Comment on lines 251 to 258
// Also include any packages that are still waiting for confirmation
for id in to_confirm.iter().filter(|id| **id != pkg_id) {
let pkg = &pkg_dep_graph.packages[&id].0;
let entry = format!("{} v{}", pkg.name(), pkg.version());
if !remaining.contains(&entry) {
remaining.push(entry);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we include these? They have been published, we just don't know if the server has fully finished processing it yet or not.

As is, the current message is misleading. It says a package hasn't been published yet. As a user, that means I need to go in and publish it but then I'll get an error saying its published.

Comment on lines 243 to 250
let mut remaining: Vec<_> = original_packages
.iter()
.filter(|id| **id != pkg_id)
.map(|id| {
let pkg = &pkg_dep_graph.packages[&id].0;
format!("{} v{}", pkg.name(), pkg.version())
})
.collect();
Copy link
Contributor

@epage epage Aug 22, 2025

Choose a reason for hiding this comment

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

If I'm reading this correctly, this is grabbing the list of all packages, including those that have already been published (except for the current package)

@weihanglo
Copy link
Member

I don't understand why we have a couple of similar PR open for the same issue. Shouldn't we consolidate all the discussions in a single place?

…ead of None, eliminating the need for conditional logic
…the confusion of packages that are already uploaded but waiting for server confirmation.
…owing packages that truly need to be published, excluding those that have already been uploaded and are just waiting for server confirmation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-interacts-with-crates.io Area: interaction with registries Command-publish
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants