1 /// Command line argument parser kind of error
2 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
3 #[non_exhaustive]
4 pub enum ErrorKind {
5     /// Occurs when an [`Arg`][crate::Arg] has a set of possible values,
6     /// and the user provides a value which isn't in that set.
7     ///
8     /// # Examples
9     ///
10     /// ```rust
11     /// # use clap_builder as clap;
12     /// # use clap::{Command, Arg, error::ErrorKind};
13     /// let result = Command::new("prog")
14     ///     .arg(Arg::new("speed")
15     ///         .value_parser(["fast", "slow"]))
16     ///     .try_get_matches_from(vec!["prog", "other"]);
17     /// assert!(result.is_err());
18     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
19     /// ```
20     InvalidValue,
21 
22     /// Occurs when a user provides a flag, option, argument or subcommand which isn't defined.
23     ///
24     /// # Examples
25     ///
26     /// ```rust
27     /// # use clap_builder as clap;
28     /// # use clap::{Command, arg, error::ErrorKind};
29     /// let result = Command::new("prog")
30     ///     .arg(arg!(--flag "some flag"))
31     ///     .try_get_matches_from(vec!["prog", "--other"]);
32     /// assert!(result.is_err());
33     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnknownArgument);
34     /// ```
35     UnknownArgument,
36 
37     /// Occurs when the user provides an unrecognized [`Subcommand`] which meets the threshold for
38     /// being similar enough to an existing subcommand.
39     /// If it doesn't meet the threshold, or the 'suggestions' feature is disabled,
40     /// the more general [`UnknownArgument`] error is returned.
41     ///
42     /// # Examples
43     ///
44     /// ```rust
45     /// # #[cfg(feature = "suggestions")] {
46     /// # use clap_builder as clap;
47     /// # use clap::{Command, Arg, error::ErrorKind, };
48     /// let result = Command::new("prog")
49     ///     .subcommand(Command::new("config")
50     ///         .about("Used for configuration")
51     ///         .arg(Arg::new("config_file")
52     ///             .help("The configuration file to use")))
53     ///     .try_get_matches_from(vec!["prog", "confi"]);
54     /// assert!(result.is_err());
55     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
56     /// # }
57     /// ```
58     ///
59     /// [`Subcommand`]: crate::Subcommand
60     /// [`UnknownArgument`]: ErrorKind::UnknownArgument
61     InvalidSubcommand,
62 
63     /// Occurs when the user doesn't use equals for an option that requires equal
64     /// sign to provide values.
65     ///
66     /// ```rust
67     /// # use clap_builder as clap;
68     /// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
69     /// let res = Command::new("prog")
70     ///     .arg(Arg::new("color")
71     ///          .action(ArgAction::Set)
72     ///          .require_equals(true)
73     ///          .long("color"))
74     ///     .try_get_matches_from(vec!["prog", "--color", "red"]);
75     /// assert!(res.is_err());
76     /// assert_eq!(res.unwrap_err().kind(), ErrorKind::NoEquals);
77     /// ```
78     NoEquals,
79 
80     /// Occurs when the user provides a value for an argument with a custom validation and the
81     /// value fails that validation.
82     ///
83     /// # Examples
84     ///
85     /// ```rust
86     /// # use clap_builder as clap;
87     /// # use clap::{Command, Arg, error::ErrorKind, value_parser};
88     /// fn is_numeric(val: &str) -> Result<(), String> {
89     ///     match val.parse::<i64>() {
90     ///         Ok(..) => Ok(()),
91     ///         Err(..) => Err(String::from("value wasn't a number!")),
92     ///     }
93     /// }
94     ///
95     /// let result = Command::new("prog")
96     ///     .arg(Arg::new("num")
97     ///          .value_parser(value_parser!(u8)))
98     ///     .try_get_matches_from(vec!["prog", "NotANumber"]);
99     /// assert!(result.is_err());
100     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::ValueValidation);
101     /// ```
102     ValueValidation,
103 
104     /// Occurs when a user provides more values for an argument than were defined by setting
105     /// [`Arg::num_args`].
106     ///
107     /// # Examples
108     ///
109     /// ```rust
110     /// # use clap_builder as clap;
111     /// # use clap::{Command, Arg, error::ErrorKind};
112     /// let result = Command::new("prog")
113     ///     .arg(Arg::new("arg")
114     ///         .num_args(1..=2))
115     ///     .try_get_matches_from(vec!["prog", "too", "many", "values"]);
116     /// assert!(result.is_err());
117     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyValues);
118     /// ```
119     /// [`Arg::num_args`]: crate::Arg::num_args()
120     TooManyValues,
121 
122     /// Occurs when the user provides fewer values for an argument than were defined by setting
123     /// [`Arg::num_args`].
124     ///
125     /// # Examples
126     ///
127     /// ```rust
128     /// # use clap_builder as clap;
129     /// # use clap::{Command, Arg, error::ErrorKind};
130     /// let result = Command::new("prog")
131     ///     .arg(Arg::new("some_opt")
132     ///         .long("opt")
133     ///         .num_args(3..))
134     ///     .try_get_matches_from(vec!["prog", "--opt", "too", "few"]);
135     /// assert!(result.is_err());
136     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooFewValues);
137     /// ```
138     /// [`Arg::num_args`]: crate::Arg::num_args()
139     TooFewValues,
140 
141     /// Occurs when the user provides a different number of values for an argument than what's
142     /// been defined by setting [`Arg::num_args`] or than was implicitly set by
143     /// [`Arg::value_names`].
144     ///
145     /// # Examples
146     ///
147     /// ```rust
148     /// # use clap_builder as clap;
149     /// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
150     /// let result = Command::new("prog")
151     ///     .arg(Arg::new("some_opt")
152     ///         .long("opt")
153     ///         .action(ArgAction::Set)
154     ///         .num_args(2))
155     ///     .try_get_matches_from(vec!["prog", "--opt", "wrong"]);
156     /// assert!(result.is_err());
157     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::WrongNumberOfValues);
158     /// ```
159     ///
160     /// [`Arg::num_args`]: crate::Arg::num_args()
161     /// [`Arg::value_names`]: crate::Arg::value_names()
162     WrongNumberOfValues,
163 
164     /// Occurs when the user provides two values which conflict with each other and can't be used
165     /// together.
166     ///
167     /// # Examples
168     ///
169     /// ```rust
170     /// # use clap_builder as clap;
171     /// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
172     /// let result = Command::new("prog")
173     ///     .arg(Arg::new("debug")
174     ///         .long("debug")
175     ///         .action(ArgAction::SetTrue)
176     ///         .conflicts_with("color"))
177     ///     .arg(Arg::new("color")
178     ///         .long("color")
179     ///         .action(ArgAction::SetTrue))
180     ///     .try_get_matches_from(vec!["prog", "--debug", "--color"]);
181     /// assert!(result.is_err());
182     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
183     /// ```
184     ArgumentConflict,
185 
186     /// Occurs when the user does not provide one or more required arguments.
187     ///
188     /// # Examples
189     ///
190     /// ```rust
191     /// # use clap_builder as clap;
192     /// # use clap::{Command, Arg, error::ErrorKind};
193     /// let result = Command::new("prog")
194     ///     .arg(Arg::new("debug")
195     ///         .required(true))
196     ///     .try_get_matches_from(vec!["prog"]);
197     /// assert!(result.is_err());
198     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
199     /// ```
200     MissingRequiredArgument,
201 
202     /// Occurs when a subcommand is required (as defined by [`Command::subcommand_required`]),
203     /// but the user does not provide one.
204     ///
205     /// # Examples
206     ///
207     /// ```rust
208     /// # use clap_builder as clap;
209     /// # use clap::{Command, error::ErrorKind};
210     /// let err = Command::new("prog")
211     ///     .subcommand_required(true)
212     ///     .subcommand(Command::new("test"))
213     ///     .try_get_matches_from(vec![
214     ///         "myprog",
215     ///     ]);
216     /// assert!(err.is_err());
217     /// assert_eq!(err.unwrap_err().kind(), ErrorKind::MissingSubcommand);
218     /// # ;
219     /// ```
220     ///
221     /// [`Command::subcommand_required`]: crate::Command::subcommand_required
222     MissingSubcommand,
223 
224     /// Occurs when the user provides a value containing invalid UTF-8.
225     ///
226     /// To allow arbitrary data
227     /// - Set [`Arg::value_parser(value_parser!(OsString))`] for argument values
228     /// - Set [`Command::external_subcommand_value_parser`] for external-subcommand
229     ///   values
230     ///
231     /// # Platform Specific
232     ///
233     /// Non-Windows platforms only (such as Linux, Unix, OSX, etc.)
234     ///
235     /// # Examples
236     ///
237     /// ```rust
238     /// # #[cfg(unix)] {
239     /// # use clap_builder as clap;
240     /// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
241     /// # use std::os::unix::ffi::OsStringExt;
242     /// # use std::ffi::OsString;
243     /// let result = Command::new("prog")
244     ///     .arg(Arg::new("utf8")
245     ///         .short('u')
246     ///         .action(ArgAction::Set))
247     ///     .try_get_matches_from(vec![OsString::from("myprog"),
248     ///                                 OsString::from("-u"),
249     ///                                 OsString::from_vec(vec![0xE9])]);
250     /// assert!(result.is_err());
251     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidUtf8);
252     /// # }
253     /// ```
254     ///
255     /// [`Arg::allow_invalid_utf8`]: crate::Arg::allow_invalid_utf8
256     /// [`Command::external_subcommand_value_parser`]: crate::Command::external_subcommand_value_parser
257     InvalidUtf8,
258 
259     /// Not a true "error" as it means `--help` or similar was used.
260     /// The help message will be sent to `stdout`.
261     ///
262     /// **Note**: If the help is displayed due to an error (such as missing subcommands) it will
263     /// be sent to `stderr` instead of `stdout`.
264     ///
265     /// # Examples
266     ///
267     /// ```rust
268     /// # #[cfg(feature = "help")] {
269     /// # use clap_builder as clap;
270     /// # use clap::{Command, Arg, error::ErrorKind};
271     /// let result = Command::new("prog")
272     ///     .try_get_matches_from(vec!["prog", "--help"]);
273     /// assert!(result.is_err());
274     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelp);
275     /// # }
276     /// ```
277     DisplayHelp,
278 
279     /// Occurs when either an argument or a [`Subcommand`] is required, as defined by
280     /// [`Command::arg_required_else_help`] , but the user did not provide
281     /// one.
282     ///
283     /// # Examples
284     ///
285     /// ```rust
286     /// # use clap_builder as clap;
287     /// # use clap::{Command, Arg, error::ErrorKind, };
288     /// let result = Command::new("prog")
289     ///     .arg_required_else_help(true)
290     ///     .subcommand(Command::new("config")
291     ///         .about("Used for configuration")
292     ///         .arg(Arg::new("config_file")
293     ///             .help("The configuration file to use")))
294     ///     .try_get_matches_from(vec!["prog"]);
295     /// assert!(result.is_err());
296     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand);
297     /// ```
298     ///
299     /// [`Subcommand`]: crate::Subcommand
300     /// [`Command::arg_required_else_help`]: crate::Command::arg_required_else_help
301     DisplayHelpOnMissingArgumentOrSubcommand,
302 
303     /// Not a true "error" as it means `--version` or similar was used.
304     /// The message will be sent to `stdout`.
305     ///
306     /// # Examples
307     ///
308     /// ```rust
309     /// # use clap_builder as clap;
310     /// # use clap::{Command, Arg, error::ErrorKind};
311     /// let result = Command::new("prog")
312     ///     .version("3.0")
313     ///     .try_get_matches_from(vec!["prog", "--version"]);
314     /// assert!(result.is_err());
315     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayVersion);
316     /// ```
317     DisplayVersion,
318 
319     /// Represents an [I/O error].
320     /// Can occur when writing to `stderr` or `stdout` or reading a configuration file.
321     ///
322     /// [I/O error]: std::io::Error
323     Io,
324 
325     /// Represents a [Format error] (which is a part of [`Display`]).
326     /// Typically caused by writing to `stderr` or `stdout`.
327     ///
328     /// [`Display`]: std::fmt::Display
329     /// [Format error]: std::fmt::Error
330     Format,
331 }
332 
333 impl ErrorKind {
334     /// End-user description of the error case, where relevant
as_str(self) -> Option<&'static str>335     pub fn as_str(self) -> Option<&'static str> {
336         match self {
337             Self::InvalidValue => Some("one of the values isn't valid for an argument"),
338             Self::UnknownArgument => Some("unexpected argument found"),
339             Self::InvalidSubcommand => Some("unrecognized subcommand"),
340             Self::NoEquals => Some("equal is needed when assigning values to one of the arguments"),
341             Self::ValueValidation => Some("invalid value for one of the arguments"),
342             Self::TooManyValues => Some("unexpected value for an argument found"),
343             Self::TooFewValues => Some("more values required for an argument"),
344             Self::WrongNumberOfValues => Some("too many or too few values for an argument"),
345             Self::ArgumentConflict => {
346                 Some("an argument cannot be used with one or more of the other specified arguments")
347             }
348             Self::MissingRequiredArgument => {
349                 Some("one or more required arguments were not provided")
350             }
351             Self::MissingSubcommand => Some("a subcommand is required but one was not provided"),
352             Self::InvalidUtf8 => Some("invalid UTF-8 was detected in one or more arguments"),
353             Self::DisplayHelp => None,
354             Self::DisplayHelpOnMissingArgumentOrSubcommand => None,
355             Self::DisplayVersion => None,
356             Self::Io => None,
357             Self::Format => None,
358         }
359     }
360 }
361 
362 impl std::fmt::Display for ErrorKind {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result363     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364         self.as_str().unwrap_or_default().fmt(f)
365     }
366 }
367