uutils/coreutils · error · clap::Error

InvalidUtf8

Error message

InvalidUtf8

What it means

ShortcutValueParser::parse_ref requires the raw OsStr value to be valid UTF-8 before doing prefix matching against possible values; otherwise it returns clap::ErrorKind::InvalidUtf8. Clap's typed value parsers reject non-UTF-8 arguments by default.

Solutions

  1. Ensure the argument is valid UTF-8 before invoking (e.g. iconv or validate in the script)
  2. If you control the parser, use a lossy conversion or an OsStr-based matcher instead of to_str()
  3. Catch the clap error and surface a clear message to the user

Example fix

// before
let value = raw_os_str;
// after
let value = raw_os_str.to_str().ok_or_else(|| anyhow!("value must be UTF-8"))?;
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_utf8(v: &std::ffi::OsStr) -> bool { v.to_str().is_some() }

Type guard

fn as_utf8(v: &std::ffi::OsStr) -> Option<&str> { v.to_str() }

Try / catch

match parse_ref(cmd, arg, os_value) {
    Err(e) if e.kind() == clap::error::ErrorKind::InvalidUtf8 => eprintln!("argument must be valid UTF-8"),
    r => r?,
}

Prevention

When it happens

Trigger: Passing an argument containing invalid UTF-8 bytes (e.g. from a shell variable with raw bytes) to a CLI option backed by this parser; also reproduced in the unit tests with non-UTF-8 input.

Common situations: Filenames with Latin-1 or arbitrary bytes passed as option values; scripts importing data from systems with different encodings.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of uutils/coreutils@92995feca2 (2026-09-20). Data as JSON: /api/errors/05dcfbb853b14df8. Report an issue: GitHub.

Appendix: source

Thrown at src/uucore/src/lib/features/parser/shortcut_value_parser.rs:100

        ContextValue::StyledStrs(vec![format!(
            "It looks like '{value}' could match several values. Did you mean {formatted_possible_values}?"
        )
        .into()]),
    );
}

impl TypedValueParser for ShortcutValueParser {
    type Value = String;

    fn parse_ref(
        &self,
        cmd: &clap::Command,
        arg: Option<&clap::Arg>,
        value: &std::ffi::OsStr,
    ) -> Result<Self::Value, clap::Error> {
        let value = value
            .to_str()
            .ok_or(clap::Error::new(ErrorKind::InvalidUtf8))?;

        let matched_values: Vec<_> = self
            .0
            .iter()
            .filter(|x| x.get_name_and_aliases().any(|name| name.starts_with(value)))
            .collect();

        match matched_values.len() {
            0 => Err(self.generate_clap_error(cmd, arg, value, &[])),
            1 => Ok(matched_values[0].get_name().to_string()),
            _ => {
                if let Some(direct_match) = matched_values.iter().find(|x| x.get_name() == value) {
                    Ok(direct_match.get_name().to_string())
                } else {
                    Err(self.generate_clap_error(cmd, arg, value, &matched_values))
                }
            }
        }

View on GitHub (pinned to 92995feca2)