1/// Command line argument parser kind of error
2#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
3#[non_exhaustive]
4pub 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
333impl ErrorKind {
334 /// End-user description of the error case, where relevant
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
362impl std::fmt::Display for ErrorKind {
363 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364 self.as_str().unwrap_or_default().fmt(f)
365 }
366}
367