diff --git a/doc/manual/rl-next/check-warn-about-missing-paths.md b/doc/manual/rl-next/check-warn-about-missing-paths.md new file mode 100644 index 000000000..ac3e85bda --- /dev/null +++ b/doc/manual/rl-next/check-warn-about-missing-paths.md @@ -0,0 +1,33 @@ +--- +synopsis: "`--check` or `--rebuild` is clearer about a missing path" +cls: [] +issues: [fj#485] +category: "Improvements" +credits: [raito] +--- + +Previously, when running Lix with --check or --rebuild, failures often surfaced +as an unhelpful error: + +> "some outputs of '...' are not valid, so checking is not possible" + +This message could mean two different things: + +- The requested output paths don't exist at all, or, +- Some outputs exist but are not known to Lix + +Lix cannot reliably distinguish these cases, so it treated them the same. + +We've updated the error messages to clarify what Lix can determine: whether any +valid outputs (> 0) are present or whether no outputs are available. + +When no valid outputs can be found, Lix will now suggest building the derivation +normally (without --check or --rebuild) before trying again. + +When some valid outputs are present, Lix now reports which ones are valid, +shows the full list of known outputs, and also suggests building the derivation +normally. + +In the future, Lix may automate this recovery step when it knows how to rebuild +the paths, but implementing that safely requires more extensive changes to the +codebase. diff --git a/lix/libstore/build/derivation-goal.cc b/lix/libstore/build/derivation-goal.cc index 7359f8c67..e9b5baf2f 100644 --- a/lix/libstore/build/derivation-goal.cc +++ b/lix/libstore/build/derivation-goal.cc @@ -353,9 +353,25 @@ try { if (buildMode == bmRepair && allValid) { co_return TRY_AWAIT(repairClosure()); } - if (buildMode == bmCheck && !allValid) - throw Error("some outputs of '%s' are not valid, so checking is not possible", - worker.store.printStorePath(drvPath)); + + if (buildMode == bmCheck && validOutputs.empty()) { + throw Error( + "'%s' has no valid outputs registered in the store, build it first and re-run the " + "check command after that", + worker.store.printStorePath(drvPath) + ); + } else if (buildMode == bmCheck && !allValid) { + auto wantedOutputsStr = wantedOutputs.to_string(); + auto validOutputsNames = concatStringsSep(", ", std::views::keys(validOutputs)); + throw Error( + "Not all outputs of '%s' are registered and valid in this store ('%s' are available, " + "'%s' are missing). " + "Rebuild the derivation normally and re-run the check command after that", + worker.store.printStorePath(drvPath), + validOutputsNames == "" ? "none" : validOutputsNames, + wantedOutputsStr == "*" ? "all" : wantedOutputsStr + ); + } /* Nothing to wait for; tail call */ co_return TRY_AWAIT(gaveUpOnSubstitution()); diff --git a/tests/functional2/build/test_fixed.py b/tests/functional2/build/test_fixed.py index 3581df49c..f7ca44b5c 100644 --- a/tests/functional2/build/test_fixed.py +++ b/tests/functional2/build/test_fixed.py @@ -46,8 +46,7 @@ def test_good(nix: Nix): @with_files(get_global_asset_pack("fixed")) def test_check(nix: Nix): res = nix.nix_build(["fixed.nix", "-A", "check", "--check"]).run().expect(1) - assert "some outputs of " in res.stderr_plain - assert "are not valid, so checking is not possible" in res.stderr_plain + assert "has no valid outputs registered in the store" in res.stderr_plain @with_files(get_global_asset_pack("fixed"))