1 /// Command line argument parser kind of error
2 #[derive(Debug, Copy, Clone, PartialEq)]
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::{Command, Arg, ErrorKind};
12     /// let result = Command::new("prog")
13     ///     .arg(Arg::new("speed")
14     ///         .value_parser(["fast", "slow"]))
15     ///     .try_get_matches_from(vec!["prog", "other"]);
16     /// assert!(result.is_err());
17     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
18     /// ```
19     InvalidValue,
20 
21     /// Occurs when a user provides a flag, option, argument or subcommand which isn't defined.
22     ///
23     /// # Examples
24     ///
25     /// ```rust
26     /// # use clap::{Command, arg, ErrorKind};
27     /// let result = Command::new("prog")
28     ///     .arg(arg!(--flag "some flag"))
29     ///     .try_get_matches_from(vec!["prog", "--other"]);
30     /// assert!(result.is_err());
31     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnknownArgument);
32     /// ```
33     UnknownArgument,
34 
35     /// Occurs when the user provides an unrecognized [`Subcommand`] which meets the threshold for
36     /// being similar enough to an existing subcommand.
37     /// If it doesn't meet the threshold, or the 'suggestions' feature is disabled,
38     /// the more general [`UnknownArgument`] error is returned.
39     ///
40     /// # Examples
41     ///
42     #[cfg_attr(not(feature = "suggestions"), doc = " ```no_run")]
43     #[cfg_attr(feature = "suggestions", doc = " ```")]
44     /// # use clap::{Command, Arg, ErrorKind, };
45     /// let result = Command::new("prog")
46     ///     .subcommand(Command::new("config")
47     ///         .about("Used for configuration")
48     ///         .arg(Arg::new("config_file")
49     ///             .help("The configuration file to use")))
50     ///     .try_get_matches_from(vec!["prog", "confi"]);
51     /// assert!(result.is_err());
52     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
53     /// ```
54     ///
55     /// [`Subcommand`]: crate::Subcommand
56     /// [`UnknownArgument`]: ErrorKind::UnknownArgument
57     InvalidSubcommand,
58 
59     /// Occurs when the user provides an unrecognized [`Subcommand`] which either
60     /// doesn't meet the threshold for being similar enough to an existing subcommand,
61     /// or the 'suggestions' feature is disabled.
62     /// Otherwise the more detailed [`InvalidSubcommand`] error is returned.
63     ///
64     /// This error typically happens when passing additional subcommand names to the `help`
65     /// subcommand. Otherwise, the more general [`UnknownArgument`] error is used.
66     ///
67     /// # Examples
68     ///
69     /// ```rust
70     /// # use clap::{Command, Arg, ErrorKind, };
71     /// let result = Command::new("prog")
72     ///     .subcommand(Command::new("config")
73     ///         .about("Used for configuration")
74     ///         .arg(Arg::new("config_file")
75     ///             .help("The configuration file to use")))
76     ///     .try_get_matches_from(vec!["prog", "help", "nothing"]);
77     /// assert!(result.is_err());
78     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnrecognizedSubcommand);
79     /// ```
80     ///
81     /// [`Subcommand`]: crate::Subcommand
82     /// [`InvalidSubcommand`]: ErrorKind::InvalidSubcommand
83     /// [`UnknownArgument`]: ErrorKind::UnknownArgument
84     UnrecognizedSubcommand,
85 
86     /// Occurs when the user provides an empty value for an option that does not allow empty
87     /// values.
88     ///
89     /// # Examples
90     ///
91     /// ```rust
92     /// # use clap::{Command, Arg, ErrorKind};
93     /// let res = Command::new("prog")
94     ///     .arg(Arg::new("color")
95     ///          .takes_value(true)
96     ///          .forbid_empty_values(true)
97     ///          .long("color"))
98     ///     .try_get_matches_from(vec!["prog", "--color="]);
99     /// assert!(res.is_err());
100     /// assert_eq!(res.unwrap_err().kind(), ErrorKind::EmptyValue);
101     /// ```
102     EmptyValue,
103 
104     /// Occurs when the user doesn't use equals for an option that requires equal
105     /// sign to provide values.
106     ///
107     /// ```rust
108     /// # use clap::{Command, Arg, ErrorKind};
109     /// let res = Command::new("prog")
110     ///     .arg(Arg::new("color")
111     ///          .takes_value(true)
112     ///          .require_equals(true)
113     ///          .long("color"))
114     ///     .try_get_matches_from(vec!["prog", "--color", "red"]);
115     /// assert!(res.is_err());
116     /// assert_eq!(res.unwrap_err().kind(), ErrorKind::NoEquals);
117     /// ```
118     NoEquals,
119 
120     /// Occurs when the user provides a value for an argument with a custom validation and the
121     /// value fails that validation.
122     ///
123     /// # Examples
124     ///
125     /// ```rust
126     /// # use clap::{Command, Arg, ErrorKind};
127     /// fn is_numeric(val: &str) -> Result<(), String> {
128     ///     match val.parse::<i64>() {
129     ///         Ok(..) => Ok(()),
130     ///         Err(..) => Err(String::from("Value wasn't a number!")),
131     ///     }
132     /// }
133     ///
134     /// let result = Command::new("prog")
135     ///     .arg(Arg::new("num")
136     ///          .validator(is_numeric))
137     ///     .try_get_matches_from(vec!["prog", "NotANumber"]);
138     /// assert!(result.is_err());
139     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::ValueValidation);
140     /// ```
141     ValueValidation,
142 
143     /// Occurs when a user provides more values for an argument than were defined by setting
144     /// [`Arg::max_values`].
145     ///
146     /// # Examples
147     ///
148     /// ```rust
149     /// # use clap::{Command, Arg, ErrorKind};
150     /// let result = Command::new("prog")
151     ///     .arg(Arg::new("arg")
152     ///         .max_values(2))
153     ///     .try_get_matches_from(vec!["prog", "too", "many", "values"]);
154     /// assert!(result.is_err());
155     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyValues);
156     /// ```
157     /// [`Arg::max_values`]: crate::Arg::max_values()
158     TooManyValues,
159 
160     /// Occurs when the user provides fewer values for an argument than were defined by setting
161     /// [`Arg::min_values`].
162     ///
163     /// # Examples
164     ///
165     /// ```rust
166     /// # use clap::{Command, Arg, ErrorKind};
167     /// let result = Command::new("prog")
168     ///     .arg(Arg::new("some_opt")
169     ///         .long("opt")
170     ///         .min_values(3))
171     ///     .try_get_matches_from(vec!["prog", "--opt", "too", "few"]);
172     /// assert!(result.is_err());
173     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooFewValues);
174     /// ```
175     /// [`Arg::min_values`]: crate::Arg::min_values()
176     TooFewValues,
177 
178     /// Occurs when a user provides more occurrences for an argument than were defined by setting
179     /// [`Arg::max_occurrences`].
180     ///
181     /// # Examples
182     ///
183     /// ```rust
184     /// # use clap::{Command, Arg, ErrorKind};
185     /// let result = Command::new("prog")
186     ///     .arg(Arg::new("verbosity")
187     ///         .short('v')
188     ///         .max_occurrences(2))
189     ///     .try_get_matches_from(vec!["prog", "-vvv"]);
190     /// assert!(result.is_err());
191     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyOccurrences);
192     /// ```
193     /// [`Arg::max_occurrences`]: crate::Arg::max_occurrences()
194     TooManyOccurrences,
195 
196     /// Occurs when the user provides a different number of values for an argument than what's
197     /// been defined by setting [`Arg::number_of_values`] or than was implicitly set by
198     /// [`Arg::value_names`].
199     ///
200     /// # Examples
201     ///
202     /// ```rust
203     /// # use clap::{Command, Arg, ErrorKind};
204     /// let result = Command::new("prog")
205     ///     .arg(Arg::new("some_opt")
206     ///         .long("opt")
207     ///         .takes_value(true)
208     ///         .number_of_values(2))
209     ///     .try_get_matches_from(vec!["prog", "--opt", "wrong"]);
210     /// assert!(result.is_err());
211     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::WrongNumberOfValues);
212     /// ```
213     ///
214     /// [`Arg::number_of_values`]: crate::Arg::number_of_values()
215     /// [`Arg::value_names`]: crate::Arg::value_names()
216     WrongNumberOfValues,
217 
218     /// Occurs when the user provides two values which conflict with each other and can't be used
219     /// together.
220     ///
221     /// # Examples
222     ///
223     /// ```rust
224     /// # use clap::{Command, Arg, ErrorKind};
225     /// let result = Command::new("prog")
226     ///     .arg(Arg::new("debug")
227     ///         .long("debug")
228     ///         .conflicts_with("color"))
229     ///     .arg(Arg::new("color")
230     ///         .long("color"))
231     ///     .try_get_matches_from(vec!["prog", "--debug", "--color"]);
232     /// assert!(result.is_err());
233     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
234     /// ```
235     ArgumentConflict,
236 
237     /// Occurs when the user does not provide one or more required arguments.
238     ///
239     /// # Examples
240     ///
241     /// ```rust
242     /// # use clap::{Command, Arg, ErrorKind};
243     /// let result = Command::new("prog")
244     ///     .arg(Arg::new("debug")
245     ///         .required(true))
246     ///     .try_get_matches_from(vec!["prog"]);
247     /// assert!(result.is_err());
248     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
249     /// ```
250     MissingRequiredArgument,
251 
252     /// Occurs when a subcommand is required (as defined by [`Command::subcommand_required`]),
253     /// but the user does not provide one.
254     ///
255     /// # Examples
256     ///
257     /// ```rust
258     /// # use clap::{Command, ErrorKind};
259     /// let err = Command::new("prog")
260     ///     .subcommand_required(true)
261     ///     .subcommand(Command::new("test"))
262     ///     .try_get_matches_from(vec![
263     ///         "myprog",
264     ///     ]);
265     /// assert!(err.is_err());
266     /// assert_eq!(err.unwrap_err().kind(), ErrorKind::MissingSubcommand);
267     /// # ;
268     /// ```
269     ///
270     /// [`Command::subcommand_required`]: crate::Command::subcommand_required
271     MissingSubcommand,
272 
273     /// Occurs when the user provides multiple values to an argument which doesn't allow that.
274     ///
275     /// # Examples
276     ///
277     /// ```rust
278     /// # use clap::{Command, Arg, ErrorKind};
279     /// let result = Command::new("prog")
280     ///     .arg(Arg::new("debug")
281     ///         .long("debug")
282     ///         .multiple_occurrences(false))
283     ///     .try_get_matches_from(vec!["prog", "--debug", "--debug"]);
284     /// assert!(result.is_err());
285     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnexpectedMultipleUsage);
286     /// ```
287     UnexpectedMultipleUsage,
288 
289     /// Occurs when the user provides a value containing invalid UTF-8.
290     ///
291     /// To allow arbitrary data
292     /// - Set [`Arg::allow_invalid_utf8`] for argument values
293     /// - Set [`Command::allow_invalid_utf8_for_external_subcommands`] for external-subcommand
294     ///   values
295     ///
296     /// # Platform Specific
297     ///
298     /// Non-Windows platforms only (such as Linux, Unix, OSX, etc.)
299     ///
300     /// # Examples
301     ///
302     #[cfg_attr(not(unix), doc = " ```ignore")]
303     #[cfg_attr(unix, doc = " ```")]
304     /// # use clap::{Command, Arg, ErrorKind};
305     /// # use std::os::unix::ffi::OsStringExt;
306     /// # use std::ffi::OsString;
307     /// let result = Command::new("prog")
308     ///     .arg(Arg::new("utf8")
309     ///         .short('u')
310     ///         .takes_value(true))
311     ///     .try_get_matches_from(vec![OsString::from("myprog"),
312     ///                                 OsString::from("-u"),
313     ///                                 OsString::from_vec(vec![0xE9])]);
314     /// assert!(result.is_err());
315     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidUtf8);
316     /// ```
317     ///
318     /// [`Arg::allow_invalid_utf8`]: crate::Arg::allow_invalid_utf8
319     /// [`Command::allow_invalid_utf8_for_external_subcommands`]: crate::Command::allow_invalid_utf8_for_external_subcommands
320     InvalidUtf8,
321 
322     /// Not a true "error" as it means `--help` or similar was used.
323     /// The help message will be sent to `stdout`.
324     ///
325     /// **Note**: If the help is displayed due to an error (such as missing subcommands) it will
326     /// be sent to `stderr` instead of `stdout`.
327     ///
328     /// # Examples
329     ///
330     /// ```rust
331     /// # use clap::{Command, Arg, ErrorKind};
332     /// let result = Command::new("prog")
333     ///     .try_get_matches_from(vec!["prog", "--help"]);
334     /// assert!(result.is_err());
335     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelp);
336     /// ```
337     DisplayHelp,
338 
339     /// Occurs when either an argument or a [`Subcommand`] is required, as defined by
340     /// [`Command::arg_required_else_help`] , but the user did not provide
341     /// one.
342     ///
343     /// # Examples
344     ///
345     /// ```rust
346     /// # use clap::{Command, Arg, ErrorKind, };
347     /// let result = Command::new("prog")
348     ///     .arg_required_else_help(true)
349     ///     .subcommand(Command::new("config")
350     ///         .about("Used for configuration")
351     ///         .arg(Arg::new("config_file")
352     ///             .help("The configuration file to use")))
353     ///     .try_get_matches_from(vec!["prog"]);
354     /// assert!(result.is_err());
355     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand);
356     /// ```
357     ///
358     /// [`Subcommand`]: crate::Subcommand
359     /// [`Command::arg_required_else_help`]: crate::Command::arg_required_else_help
360     DisplayHelpOnMissingArgumentOrSubcommand,
361 
362     /// Not a true "error" as it means `--version` or similar was used.
363     /// The message will be sent to `stdout`.
364     ///
365     /// # Examples
366     ///
367     /// ```rust
368     /// # use clap::{Command, Arg, ErrorKind};
369     /// let result = Command::new("prog")
370     ///     .version("3.0")
371     ///     .try_get_matches_from(vec!["prog", "--version"]);
372     /// assert!(result.is_err());
373     /// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayVersion);
374     /// ```
375     DisplayVersion,
376 
377     /// Occurs when using the [`ArgMatches::value_of_t`] and friends to convert an argument value
378     /// into type `T`, but the argument you requested wasn't used. I.e. you asked for an argument
379     /// with name `config` to be converted, but `config` wasn't used by the user.
380     ///
381     /// [`ArgMatches::value_of_t`]: crate::ArgMatches::value_of_t()
382     ArgumentNotFound,
383 
384     /// Represents an [I/O error].
385     /// Can occur when writing to `stderr` or `stdout` or reading a configuration file.
386     ///
387     /// [I/O error]: std::io::Error
388     Io,
389 
390     /// Represents a [Format error] (which is a part of [`Display`]).
391     /// Typically caused by writing to `stderr` or `stdout`.
392     ///
393     /// [`Display`]: std::fmt::Display
394     /// [Format error]: std::fmt::Error
395     Format,
396 }
397 
398 impl ErrorKind {
399     /// End-user description of the error case, where relevant
as_str(self) -> Option<&'static str>400     pub fn as_str(self) -> Option<&'static str> {
401         match self {
402             Self::InvalidValue => Some("One of the values isn't valid for an argument"),
403             Self::UnknownArgument => {
404                 Some("Found an argument which wasn't expected or isn't valid in this context")
405             }
406             Self::InvalidSubcommand => Some("A subcommand wasn't recognized"),
407             Self::UnrecognizedSubcommand => Some("A subcommand wasn't recognized"),
408             Self::EmptyValue => Some("An argument requires a value but none was supplied"),
409             Self::NoEquals => Some("Equal is needed when assigning values to one of the arguments"),
410             Self::ValueValidation => Some("Invalid value for one of the arguments"),
411             Self::TooManyValues => Some("An argument received an unexpected value"),
412             Self::TooFewValues => Some("An argument requires more values"),
413             Self::TooManyOccurrences => Some("An argument occurred too many times"),
414             Self::WrongNumberOfValues => Some("An argument received too many or too few values"),
415             Self::ArgumentConflict => {
416                 Some("An argument cannot be used with one or more of the other specified arguments")
417             }
418             Self::MissingRequiredArgument => {
419                 Some("One or more required arguments were not provided")
420             }
421             Self::MissingSubcommand => Some("A subcommand is required but one was not provided"),
422             Self::UnexpectedMultipleUsage => {
423                 Some("An argument was provided more than once but cannot be used multiple times")
424             }
425             Self::InvalidUtf8 => Some("Invalid UTF-8 was detected in one or more arguments"),
426             Self::DisplayHelp => None,
427             Self::DisplayHelpOnMissingArgumentOrSubcommand => None,
428             Self::DisplayVersion => None,
429             Self::ArgumentNotFound => Some("An argument wasn't found"),
430             Self::Io => None,
431             Self::Format => None,
432         }
433     }
434 }
435 
436 impl std::fmt::Display for ErrorKind {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result437     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
438         self.as_str().unwrap_or_default().fmt(f)
439     }
440 }
441