Repository navigation
nvx-rs: make the error codes and Error's constructors private (SL6.8c) - #1552
Merged
Pedro Henrique Penna (ppenna) merged 3 commits intoNov 12, 2026
Conversation
Contributor
This pull request changes existing testsIt modifies or removes 5 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests. Test code
Relocated unchanged: 0; added: 1. Compared the merge base |
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are recorded for the error API visibility changes.
No open issues 🎉
What changed in this PR
Implements SL6.8c of #1126 in the NVX library-slimming workstream. Library callers distinguish errors through ErrorKind, messages and sources, while error construction and stable CLI codes become crate-private.
Changes:
- Makes
ErrorCode,Error::codeand error constructors crate-private, with feature gates matching their callers. - Removes three unused error codes and the unused
not_foundconstructor without changing CLI diagnostics or exit statuses. - Adapts tests, updates documentation and removes the private API from Linux and Windows snapshots.
| File | Description |
|---|---|
scripts/test_nvx_tools.py |
Updates a comment to describe CLI codes rather than the public enum. |
nvx-rs/tests/cli/openvmm.rs |
Uses boxed errors instead of constructing library errors in fixtures. |
nvx-rs/src/lib.rs |
Restricts the ErrorCode re-export to crate-internal host use. |
nvx-rs/src/host/snapshot/manifest.rs |
Documents parse failures by their public error kind. |
nvx-rs/src/host/snapshot/key.rs |
Documents decoding failures by their public error kind. |
nvx-rs/src/host/cli/mod.rs |
Removes a documentation link to the now-private code type. |
nvx-rs/src/error/tests.rs |
Keeps the code inventory test-local and adapts constructor checks. |
nvx-rs/src/error.rs |
Narrows visibility, gates constructors and removes unused error items. |
nvx-rs/README.md |
Separates public error kinds from private CLI codes. |
nvx-rs/public-api/windows.txt |
Records the reduced Windows error API. |
nvx-rs/public-api/linux.txt |
Records the reduced Linux error API. |
doc/usage.md |
Clarifies library error kinds and removes obsolete CLI codes. |
Review effort: Balanced
This was referenced Nov 12, 2026
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/slim-sl6-5b-export-paths-only
branch
from
November 12, 2026 22:01
21ce29a to
03b7ccb
Compare
Base automatically changed from
agents/slim-sl6-5b-export-paths-only
to
feature/nvx-refactor
November 12, 2026 22:27
SL6.8c (#1126) makes ErrorCode and Error's constructors crate-private. Once they are, the warning-denied build of the cli feature, which builds every code of the crate that makes errors, finds three codes and one constructor that nothing makes or calls any more: only the public API and the tests named them. This deletes them first, so that the change of visibility leaves every feature set's build clean: - template-ineligible and template-tombstoned, which the template store reported until it left (SL6.2a, #1121), and sandbox-leased, which the sandbox store reported until it left (SL6.1, #1121). No NVX program reports them, so the CLI prints the same code for every error that it reports. - Error::not_found, which nothing calls. The README's and doc/usage.md's tables of the codes lose the three rows, as the test that compares the README with ErrorCode::ALL, and the test that compares the two tables, require. The public API snapshots lose 4 lines on each platform, the four items, and gain none. Part of #1126 (SL6.8c). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.8c (#1126) makes Error's constructors and ErrorCode crate-private, and ErrorCode::ALL, which only tests read, goes once the warning-denied builds find it unused. Two tests reached them, which they cannot once those are private, so each keeps its assertions without them: - cold_run_expected, which projects a cold-run fixture onto the public VM contract, built nvx's Unsupported errors for the two fixtures that it cannot project. It now refuses them with errors of its own, as a caller that built nvx's errors must, and still passes on the public contract's own errors. The dry-run and one-shot tests show either only when they report an unexpected refusal. - The error module's tests list the codes themselves, in the order of the README's table, in place of ErrorCode::ALL, for codes_are_unique_lowercase_words_joined_by_hyphens and the_readme_documents_every_code_with_its_kind. They make their errors with Error::new and Error::unavailable, which every feature set builds, in place of Error::io and Error::unsupported, which only the host and guest builds will: errors_keep_their_kind_message_and_cause and codes_determine_kinds check the same kinds, codes, messages and causes. Part of #1126 (SL6.8c). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Callers act on nvx's failures by an error's kind, message and source, but ErrorCode, Error::code and Error's constructors were public: the codes, which serve the CLI's output, were part of the library's API, and any caller could fabricate nvx's errors. They become crate-private where they are, so that nvx alone makes its errors, and its public error is Error, ErrorKind and Result: - ErrorCode, with as_str and kind, and Error::code become pub(crate), and the crate root re-exports ErrorCode to the crate only, for the host and the CLI, which name it there. ErrorCode loses #[non_exhaustive], which only bound other crates, and ErrorCode::ALL, which only tests read. - Error::new, its constructor of each kind, and with_source become pub(crate), gated by the features of their callers: unsupported and io build with the host or the guest, exited, protocol, timed_out and other with the host, and new, unavailable and with_source with every feature set. - The CLI keeps its codes, and prints each error's code with the same messages and exit statuses. Most finer codes come from the CLI alone, and the CLI reads Error::code, as nvx-init and tests do, so the builds without the cli feature allow both to be unused. - Error keeps kind, message, into_parts, its display and its source, and ErrorKind its variants, as_str and its display. Their docs, and those of SnapshotKey::from_bytes and SnapshotManifest::parse, name kinds and no codes, and the docs of the CLI's hidden module no longer link the private ErrorCode. The README's Errors section describes the error by its kind, which only nvx makes, and its Error codes section the codes that the CLI prints, which the library keeps private. doc/usage.md, and a comment of the test that compares the two tables, follow. The public API snapshots lose 42 lines on each platform, ErrorCode with its variants and methods, and Error's constructors and code, and gain none. Part of #1126 (SL6.8c). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/slim-sl6-8c-error-codes-private
branch
from
November 12, 2026 22:31
5d18353 to
b92df2b
Compare
Pedro Henrique Penna (ppenna)
marked this pull request as ready for review
November 12, 2026 22:31
Pedro Henrique Penna (ppenna)
merged commit Nov 12, 2026
f5cc2aa
into
feature/nvx-refactor
86 checks passed
Pedro Henrique Penna (ppenna)
deleted the
agents/slim-sl6-8c-error-codes-private
branch
November 12, 2026 22:48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #1126 (SL6.8c, "Callers tell
nvx's errors apart by their kinds; the error codes are private"). Parent #1088, umbrella #1076.SL6.8c needs SL6.4 (#1533), SL6.5b (#1549) and SL6.7b (#1539), all merged.
What and why
Callers act on
nvx's failures by an error's kind, message and source, butErrorCode,Error::codeandError's constructors were public: the stable codes, which serve the CLI's output, were part of the library's API, and any caller could fabricatenvx's errors. This PR does SL6.8c's Scope:nvx's public error isError,ErrorKindandResult,nvxalone makes its errors, and the CLI prints the same code, message and exit status for every error. Three commits:nvx-rs: delete the error codes and the constructor that nothing makes(a3a1db81): once the codes and constructors are crate-private, the warning-denied build of theclifeature, which builds every producer of a code, finds three codes and one constructor that nothing makes or calls:template-ineligibleandtemplate-tombstoned, which the template store reported until SL6.2a deleted it,sandbox-leased, which the sandbox store reported until SL6.1 deleted it, andError::not_found. They go first, with their rows in the README's anddoc/usage.md's tables of codes, so that the change of visibility leaves every feature set's build clean. No NVX program reports them, so the CLI's output doesn't change. The API snapshots lose 4 lines on each platform.tests: stop building nvx's errors and listing its codes through its API(8484381f): the two tests that reached the API that goes keep their assertions without it (Test changes, below). It changes no production code, so it passes on its own, before the visibility change.nvx-rs: make the error codes and Error's constructors private(b92df2b8):ErrorCode, withas_strandkind, becomespub(crate)where it is, and loses#[non_exhaustive], which only bound other crates, andErrorCode::ALL, which only tests read. The crate root re-exports it to the crate only (pub(crate) use, withhost), for the host and the CLI, which name it there.Error::codebecomespub(crate).Error::new, its constructor of each kind andwith_sourcebecomepub(crate), gated by the features of their callers:unsupportedandiobuild withhostor the Linux guest,exited,protocol,timed_outandotherwithhost, andnew,unavailableandwith_sourcein every feature set.error[CODE]: MESSAGEandPROG: error[CODE]: MESSAGEwith the same codes, messages and exit statuses, through the sameExitmappings; no file ofhost::clichanges but a doc link. Most finer codes come from the CLI alone, and the CLI readsError::code, as nvx-init's boot and the host's unit tests do, so the builds withoutcliallowErrorCode's variants andError::codeto be unused (cfg_attr(not(feature = "cli"), allow(dead_code, reason = …)), ashost::config::reject_container_pathdoes). The builds withcliallow nothing, and find no unused code or helper.Errorkeepskind,message,into_parts, its display and its source, andErrorKindits variants,as_strand its display. No error's kind, message or source changes.Error,Error::kind,ErrorKindandinto_partsname kinds and no codes, as do those ofSnapshotKey::from_bytesandSnapshotManifest::parse, which linkedErrorCode::FormatUnsupported(nowErrorKind::Io, its kind, as before), and the docs of the CLI's hidden module no longer link the privateErrorCode. The README's Errors section describes the error by its kind, which onlynvxmakes, and its Error codes section the codes that the CLI prints, which the library keeps private;doc/usage.mdand a comment oftest_usage_documents_every_error_code_of_nvx_rsfollow. No example built or matchednvx's errors by code:host-workflowsmatches kinds already.ErrorCodewith its variants,ALL,as_strandkind, andError's constructors andcode. With the first commit's 4, they lose 45 lines on each platform and gain none:nvx::Errorlistsinto_parts,kindandmessageonly.BOOT_CONTRACT_VERSIONandCONTROL_CONTRACT_REVISIONdon't change.Size
Measured against
14ea1a45a6d(feature/nvx-refactorwith SL6.5b), by #1076's rules.nvx-rs/src/error.rs: 10 core lines. It adds 29 code lines: 13 make itemspub(crate)and 6 gate the constructors by their callers' features, which don't count; the 8 lines of the twoallow(dead_code)attributes for the builds withoutcli, and 2 lines ofErrorCode::kind, whose arms the deleted codes shorten, do. It deletes 61 code lines: the three codes,ALLandnot_found. The orchestrator's stop for this slice, deletions included, is 200 core lines.nvx-rs/src/lib.rs: 0. Its 3 lines make the re-export crate-private and gate it byhost.Old tests of the area
tests/cli.rsandtests/cli/, the CLI's unit tests that check codes (host::cli'sargs,download,sandbox,session,snapshots,storeand others), the unit tests that check the codes that the host makes (host::snapshot::{key, manifest},host::config,host::network,host::vm),every_kind_has_a_code_of_its_own_spelling, andscripts/test_nvx_tools.py'stest_usage_documents_every_error_code_of_nvx_rs, which compares the README's codes withdoc/usage.md's and their statuses.errorand the helpercold_run_expected(Test changes).The 54 CLI tests that check printed codes, messages and exit statuses, all passing unchanged
nvx-rs/tests/cli.rs:an_error_after_a_workloads_output_starts_a_line_of_its_own,an_error_is_one_line_whatever_the_values_that_its_message_names,exec_and_stop_tell_a_directory_without_a_sandbox_from_a_stopped_sandbox,a_sandbox_whose_configuration_names_another_layer_role_does_not_start,a_distro_manifest_path_whose_lookup_fails_refuses_provision_and_start,runtime_records_of_earlier_stores_are_refused_without_migration,network_policy_files_compile_into_the_typed_policy,a_run_passes_openvmm_no_handle_of_its_caller,artifacts_default_to_the_checkout_that_holds_the_executable,top_level_usage_errors_exit_with_status_2,usage_errors_print_the_one_line_usage_of_their_parser,run_guides_failed_cold_boots_on_cpus_that_no_built_in_profile_servesnvx-rs/tests/cli/download.rs:run_downloads_the_release_of_a_checkout_without_artifacts,run_downloads_before_checking_mount_sources_that_installation_can_create,run_downloads_nothing_over_some_artifacts,commands_download_nothing_for_options_that_they_refuse,restores_download_nothing_for_snapshots_that_they_cannot_open,start_downloads_the_release_of_a_checkout_without_artifacts,the_variable_turns_downloads_off_with_0,roots_that_are_no_git_checkout_download_nothing,download_installs_into_git_checkouts_of_nvx_alone,download_installs_the_packages_of_this_hostnvx-rs/tests/cli/dry_run.rs:dry_runs_print_the_openvmm_command_and_launch_nothing,the_openvmm_command_of_a_run_splits_back_into_its_argumentsnvx-rs/tests/cli/egress.rs:egress_compile_prints_the_library_loweringnvx-rs/tests/cli/exec_lock.rs:exec_processes_contend_but_other_sandboxes_and_stop_proceed,a_retry_that_waits_for_the_lifecycle_lock_past_the_deadline_is_busy,exec_cannot_recreate_admission_after_cleanup_removes_provisioned_state,a_replaced_exec_lock_entry_is_refused_before_contacting_the_vmnvx-rs/tests/cli/formats.rs:old_configuration_formats_are_refused_without_migration,invalid_recorded_roots_are_refused_before_spawnnvx-rs/tests/cli/lifecycle.rs:managed_execs_exit_with_the_workload_status,managed_execs_stream_their_standard_input_and_output,provision_refuses_shares_of_its_own_files,provision_refuses_a_share_that_holds_the_state_directory_that_it_would_create,provision_refuses_a_share_that_holds_a_state_directory_that_only_a_verbatim_path_names,provision_refuses_a_share_of_the_roots_openvmm_whatever_the_variable_names,start_refuses_recorded_shares_of_its_own_files,start_refuses_a_share_that_came_to_reach_its_own_filesnvx-rs/tests/cli/one_shot.rs:one_shot_runs_exit_with_the_workload_or_openvmm_status,forwarding_failure_stops_the_verified_vm_during_connect_and_handshake,terminal_ctrl_c_cancels_boot_and_handshake_and_restores_the_terminal,windows_terminal_ctrl_c_helper,cold_runs_refuse_existing_and_missing_parent_reports_before_launch,a_cold_spawn_without_a_child_removes_its_private_directory,a_foreground_output_error_keeps_the_requested_native_reportnvx-rs/tests/cli/sandbox_run.rs:runs_refuse_shares_of_their_own_files,a_run_refuses_a_share_of_the_openvmm_that_the_variable_names,a_run_refuses_a_share_of_its_vm_directory,a_run_whose_guest_exits_during_startup_fails_as_a_start_does,a_run_whose_workload_the_guest_refuses_stops_its_vmnvx-rs/tests/cli/usage.rs:usage_errors_exit_2_and_name_the_optionnvx-rs/tests/cli/validation.rs:unbalanced_disk_paths_fail_before_launch_or_provision,validation_errors_exit_1_before_any_side_effectBetween them they check the codes
argument-invalid,argument-missing,argument-unrecognized,artifact-missing,endpoint-closed,exec-refused,exited,format-unsupported,io,outcome-report-exists,sandbox-busy,sandbox-not-provisioned,unavailableandunsupported, with exit status 2 for usage errors and 1 for others.Test changes
python scripts/check_test_changes.py --base 14ea1a45a6dlists 5 changes to existing tests and 1 added item, hencetests-modified:nvx-rs/tests/cli/openvmm.rs,cold_run_expected: it projects a cold-run fixture onto the public VM contract, and builtnvx'sUnsupportederrors for the two fixtures that it cannot project, which it can no longer do. It now refuses them with errors of its own (Result<Self, Box<dyn std::error::Error>>), as a caller that builtnvx's errors must, and still passes on the public contract's own errors with?. Its callers,dry_run::dry_runs_print_the_openvmm_command_and_launch_nothing,dry_run::the_openvmm_command_of_a_run_splits_back_into_its_arguments,one_shot::one_shot_runs_exit_with_the_workload_or_openvmm_statusandone_shot::both_cold_modes_keep_their_foreground_output_and_owned_exit_status, show the error only when they report an unexpected refusal, and pass unchanged.nvx-rs/src/error/tests.rs, the unit tests of the error's owner:CODES, the 27 codes in the order of the README's table, in place ofErrorCode::ALL, which goes;codes_are_unique_lowercase_words_joined_by_hyphensandthe_readme_documents_every_code_with_its_kinditerateCODESin place ofErrorCode::ALL, with the same assertions;errors_keep_their_kind_message_and_causemakes its error withError::new(ErrorKind::Io, …)in place ofError::io(…), which builds only withhostor the guest, so thatcargo test --lib --no-default-featuresstill runs it; same assertions;codes_determine_kindschecks that a kind's constructor gives its kind's code throughError::unavailable, which every feature set builds, in place ofError::unsupported; its other assertions don't change.doc/acceptance-case-matrix.mdlists none of these tests, nor names them as coverage;check_matrix.pypasses.Validation
local_gates.py --files(fromdev) selectstest-changes,markdown-links,test-layout,code-quality, thecheck-nvx-rssteps,nvx-cliand the microVM tests; I ran them from this branch's action definitions, with Rust 1.95.0, locally on Windows and onnvx-kvm-test(Azure Linux 3, kernel 6.6, linux-kvm, virtual machine), in a temporary worktree. They ran on SL6.5a2's and SL6.5b's earlier heads first. Before this merge turn, I restacked the branch onto SL6.5b's final head,03b7ccb22dc: NVXC's chain had already deletedguest-features-missing, soErrorCode::kindand the tests' list of codes drop it, and the warning-denied builds of every feature set found nothing more to delete.feature/nvx-refactor's14ea1a45a6dis that SL6.5b, with the same tree, andgit range-diffshows=for the three commits moved onto it, so the results on that restack,944b37e636c, hold for this head,b92df2b8db1:cargo fmt --all --check-D warnings:--all-targets --all-features,--lib,--lib --no-default-features,serde,cliandtestingalone, and--lib --tests --no-default-features--target x86_64-unknown-linux-gnu, and--all-targetswith default features--target x86_64-unknown-linux-musl --no-default-features --features guest --all-targets -D warningscargo test --locked --all-featurescli113 passed, 2 ignored; every other integration test and the doc testsguest::tests fail at the base,03b7ccb22dc, on this host's kernel 6.6. With--no-fail-fast,cli123 passed, and every other integration test and the 14 doc tests passedcargo test --no-default-features --features guest --no-fail-fastguest_tools33,host_modules22,nvxs7 and the 13 doc tests passedcargo test --locked,cargo build --locked --lib --no-default-features,cargo test --locked --lib --no-default-featurescargo check --all-targets --all-features --target aarch64-apple-darwinhost/snapshot/tests.rs, is the base'sRUSTDOCFLAGS=-D warnings cargo doc --locked --no-deps --all-features--target x86_64-unknown-linux-gnucargo +1.89 check --locked --all-targets --all-featurespython scripts/public_api.pycheck_test_layout.py,check_markdown_links.py,check_test_changes.py,check_matrix.py <worktree> 99d2022085f, Ruff check and format, Pyright for Linux and Windows, andtest_usage_documents_every_error_code_of_nvx_rs14ea1a45a6d: Clippy-D warningsfor--all-targets --all-features,--lib --no-default-featuresand--lib --tests --no-default-features, and the error module's tests, pass after each of the three commits.python3 scripts/nvx.py test-microvm --backend kvmonb92df2b8db1, withNVX_AUTO_DOWNLOAD=0, this head's releasenvx-rs, and the artifacts of CI run 43316146269, SL6.5b's run at03b7ccb22dc, whose tree is this base's, with the OpenVMM pin14dc4116ec7: the kernel, the Alpine initramfs, the Ubuntu distro layer and scratch template, and OpenVMM, each checked by SHA-256 against the run's artifacts and OpenVMM's provenance. All 12 passed, as on the earlier heads:managed-exec-config,sandbox-gpt-layer,sandbox-lifecycle,sandbox-proxy-only,sandbox-ram-upper,snapshot-core,snapshot-tiers,untiered-network-policyandvm-lifecycle. Their failure cases check the codes that the CLI prints:snapshot-corerefuses restores witherror[unsupported],error[exited]anderror[sandbox-busy], andsandbox-lifecycle,managed-exec-configanduntiered-network-policycheck theirs;scratch-snapshotandsnapshot-rollback, andl3-l4-egress-port-ranges, which checkserror[unsupported]for each invalid port range.nvx-cligate's 22 unit-test modules ran on Windows: 1803 tests, 73 skipped; one subtest,test_private_network_ingress_script_checks_policy_and_traffic [tcp-missed], timed out after 10 s under the load of the full run, and passes alone.guest-features-missing.nvx-rson Linux and Windows, thenvx-cligates, the packages and platforms, and the microVM tests on KVM, MSHV and WHP.Left to CI:
openvmm-ci, which this PR's unchanged pin skips.