Skip to main content

aube_runtime/
error.rs

1//! Typed errors for runtime resolution and installation. Each fatal
2//! variant maps onto a stable `ERR_AUBE_*` code (see [`Error::code`])
3//! so the CLI layer can wrap them into miette diagnostics with the
4//! right exit codes.
5
6use aube_codes::errors;
7
8#[derive(Debug, thiserror::Error)]
9pub enum Error {
10    #[error(
11        "the project requires Node.js {requested} but no satisfying version is available{hint}"
12    )]
13    VersionUnsatisfied { requested: String, hint: String },
14
15    #[error("no Node.js release satisfies {requested}{platform_note}")]
16    NoMatchingVersion {
17        requested: String,
18        platform_note: String,
19    },
20
21    #[error("failed to download {url}: {reason}")]
22    DownloadFailed { url: String, reason: String },
23
24    #[error(
25        "checksum mismatch for {url}: expected sha256 {expected}, got {actual} — the archive was discarded"
26    )]
27    ChecksumMismatch {
28        url: String,
29        expected: String,
30        actual: String,
31    },
32
33    #[error("failed to extract Node.js archive: {reason}")]
34    ExtractFailed { reason: String },
35
36    /// `version` carries the full tool spec (`node@22.1.0`,
37    /// `aube@1.18.2`).
38    #[error("mise failed to install {version}: {reason}")]
39    MiseInstallFailed { version: String, reason: String },
40
41    #[error(
42        "no Node.js build is published for {platform}; set nodeDownloadMirrors to a mirror that carries one, or install Node via mise or your system package manager"
43    )]
44    UnsupportedPlatform { platform: String },
45
46    #[error("offline mode is active and {what} is not cached")]
47    Offline { what: String },
48
49    #[error("{context}: {source}")]
50    Io {
51        context: String,
52        #[source]
53        source: std::io::Error,
54    },
55}
56
57impl Error {
58    /// The stable `ERR_AUBE_*` identifier for this error.
59    pub fn code(&self) -> &'static str {
60        match self {
61            Error::VersionUnsatisfied { .. } => errors::ERR_AUBE_RUNTIME_VERSION_UNSATISFIED,
62            Error::NoMatchingVersion { .. } => errors::ERR_AUBE_RUNTIME_NO_MATCHING_VERSION,
63            Error::DownloadFailed { .. } => errors::ERR_AUBE_RUNTIME_DOWNLOAD_FAILED,
64            Error::ChecksumMismatch { .. } => errors::ERR_AUBE_RUNTIME_CHECKSUM_MISMATCH,
65            Error::ExtractFailed { .. } => errors::ERR_AUBE_RUNTIME_EXTRACT_FAILED,
66            Error::MiseInstallFailed { .. } => errors::ERR_AUBE_RUNTIME_MISE_INSTALL_FAILED,
67            Error::UnsupportedPlatform { .. } => errors::ERR_AUBE_RUNTIME_UNSUPPORTED_PLATFORM,
68            Error::Offline { .. } => errors::ERR_AUBE_OFFLINE,
69            // Generic exit code (no EXIT_TABLE entry) — a lock or
70            // rename failure is not a download failure, and the
71            // message names the failing path.
72            Error::Io { .. } => errors::ERR_AUBE_RUNTIME_IO,
73        }
74    }
75
76    pub(crate) fn io(context: impl Into<String>, source: std::io::Error) -> Self {
77        Error::Io {
78            context: context.into(),
79            source,
80        }
81    }
82}