Skip to main content

miden_client_cli/
errors.rs

1// Suppress false positive from miette+thiserror proc-macro interaction.
2#![allow(unused_assignments)]
3
4use std::error::Error;
5
6use miden_client::account::{AccountId, AddressError};
7use miden_client::keystore::KeyStoreError;
8use miden_client::vm::typed::TypedError;
9use miden_client::{
10    AccountError,
11    AccountIdError,
12    AssetError,
13    ClientError,
14    CodeBuilderError,
15    ErrorHint,
16    NetworkIdError,
17};
18use miette::Diagnostic;
19use thiserror::Error;
20
21use crate::client_binary_name;
22type SourceError = Box<dyn Error + Send + Sync>;
23
24#[derive(Debug, Diagnostic, Error)]
25pub enum CliError {
26    #[error("account error: {1}")]
27    #[diagnostic(code(cli::account_error))]
28    Account(#[source] AccountError, String),
29    #[error("account component error: {1}")]
30    #[diagnostic(code(cli::account_error))]
31    AccountComponentError(#[source] SourceError, String),
32    #[error("account id error: {1}")]
33    #[diagnostic(code(cli::accountid_error), help("Check the account ID format."))]
34    AccountId(#[source] AccountIdError, String),
35    #[error("address error: {1}")]
36    #[diagnostic(code(cli::address_error), help("Check the address format."))]
37    Address(#[source] AddressError, String),
38    #[error("asset error")]
39    #[diagnostic(code(cli::asset_error))]
40    Asset(#[source] AssetError),
41    #[error("client error")]
42    #[diagnostic(code(cli::client_error))]
43    Client {
44        #[source]
45        error: ClientError,
46        #[help]
47        help: Option<String>,
48    },
49    #[error("config error: {1}")]
50    #[diagnostic(
51        code(cli::config_error),
52        help(
53            "Check if the configuration file exists and is well-formed. If it does not exist, run `{} init` command to create it.",
54            client_binary_name().display()
55        )
56    )]
57    Config(#[source] SourceError, String),
58    #[error("configuration file not found: {0}")]
59    #[diagnostic(
60        code(cli::config_not_found),
61        help(
62            "Run `{} init` command to create a configuration file.",
63            client_binary_name().display()
64        )
65    )]
66    ConfigNotFound(String),
67    #[error("configuration file already exists: {0}")]
68    #[diagnostic(
69        code(cli::config_already_exists),
70        help(
71            "Edit the configuration file, or remove it with `{} clear-config{1}` \
72            (this deletes the whole .miden directory, including the store and keystore).",
73            client_binary_name().display(),
74        )
75    )]
76    ConfigAlreadyExists(String, String),
77    #[error("execute program error: {1}")]
78    #[diagnostic(code(cli::execute_program_error))]
79    Exec(#[source] SourceError, String),
80    #[error("export error: {0}")]
81    #[diagnostic(code(cli::export_error), help("Check the ID."))]
82    Export(String),
83    #[error("faucet error: {1}")]
84    #[diagnostic(code(cli::faucet_error))]
85    Faucet(#[source] SourceError, String),
86    #[error("import error: {0}")]
87    #[diagnostic(code(cli::import_error), help("Check the file name."))]
88    Import(String),
89    #[error("init data error: {1}")]
90    #[diagnostic(code(cli::account_error))]
91    InitDataError(#[source] SourceError, String),
92    #[error("input error: {0}")]
93    #[diagnostic(code(cli::input_error))]
94    Input(String),
95    #[error("io error")]
96    #[diagnostic(code(cli::io_error))]
97    IO(#[from] std::io::Error),
98    #[error("internal error")]
99    Internal(#[source] SourceError),
100    #[error("keystore error")]
101    #[diagnostic(code(cli::keystore_error))]
102    KeyStore(#[source] KeyStoreError),
103    #[error("missing flag: {0}")]
104    #[diagnostic(code(cli::config_error), help("Check the configuration file format."))]
105    MissingFlag(String),
106    #[error("network id error")]
107    NetworkIdError(#[from] NetworkIdError),
108    #[error("client has not been synced yet")]
109    #[diagnostic(
110        code(cli::not_synced),
111        help("Run `{} sync` first.", client_binary_name().display())
112    )]
113    NotSynced,
114    #[error("invalid argument: {0}")]
115    InvalidArgument(String),
116    // Covers both directions of the typed path: encoding arguments and decoding results. The
117    // inner error already states the whole problem, so it is shown in place of a wrapper message
118    // rather than under one, where it would be printed twice.
119    #[error(transparent)]
120    #[diagnostic(code(cli::typed_error))]
121    Typed(#[from] TypedError),
122    #[error("parse error: {1}")]
123    #[diagnostic(code(cli::parse_error), help("Check the inputs."))]
124    Parse(#[source] SourceError, String),
125    #[error("replay snapshot error")]
126    #[diagnostic(code(cli::replay_snapshot_error))]
127    ReplaySnapshot(#[source] SourceError),
128    #[error("script builder error")]
129    #[diagnostic(code(cli::script_builder_error))]
130    CodeBuilder(#[from] CodeBuilderError),
131    #[error("transaction error: {1}")]
132    #[diagnostic(code(cli::transaction_error))]
133    Transaction(#[source] SourceError, String),
134    #[error("expected full account, but got partial account: {0}")]
135    InvalidAccount(AccountId),
136}
137
138impl From<ClientError> for CliError {
139    fn from(error: ClientError) -> Self {
140        let help = Option::<ErrorHint>::from(&error).map(ErrorHint::into_help_message);
141        CliError::Client { error, help }
142    }
143}