astral-sh/ruff · error · clap::Error

InvalidUtf8

Error message

InvalidUtf8

What it means

This clap InvalidUtf8 error is raised in ruff's completion-config value parser (`parse_ref`) when the raw argument value passed on the command line is not valid UTF-8. The parser converts the `OsStr` to `&str` before further parsing and fails immediately with this error kind if conversion fails.

Solutions

  1. Re-run the command with a UTF-8 argument value
  2. Set a UTF-8 locale (e.g. `export LANG=C.UTF-8`) so filenames expand correctly
  3. Check the script generating the command line for byte-encoding mistakes

Example fix

// before
let value = value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
// after (accept OsString when non-UTF-8 is legitimate)
let value = value.to_str().ok_or_else(|| clap::Error::raw(
    clap::error::ErrorKind::InvalidUtf8,
    "argument value must be valid UTF-8",
))?;
Defensive patterns

Strategy: validation

Validate before calling

value_str = os.fsdecode(raw_arg)
try:
    value_str.encode("utf-8")
except UnicodeEncodeError:
    raise SystemExit("argument must be valid UTF-8")

Type guard

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

Try / catch

match result {
    Err(e) if e.kind() == clap::error::ErrorKind::InvalidUtf8 => eprintln!("argument must be UTF-8"),
    Err(e) => return Err(e.into()),
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Invoking ruff with an argument (e.g. a `--config`-style key=value flag handled by this parser) whose bytes are not valid UTF-8, typically by passing a binary-encoded value or a filename from a shell with non-UTF-8 locale.

Common situations: Shell environments with non-UTF-8 locales (e.g. LANG=C with latin-1 encoded filenames), scripting bugs that splice raw bytes into command lines, filenames produced by legacy Windows tooling.

Related errors


AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05). Data as JSON: /api/errors/efbd062586120cb8. Report an issue: GitHub.

Appendix: source

Thrown at crates/ruff/src/commands/completions/config.rs:121

    type Parser = OptionStringParser;

    fn value_parser() -> Self::Parser {
        OptionStringParser
    }
}

impl TypedValueParser for OptionStringParser {
    type Value = OptionString;

    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_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;

        value.parse().map_err(|()| {
            let mut error = clap::Error::new(clap::error::ErrorKind::ValueValidation).with_cmd(cmd);
            if let Some(arg) = arg {
                error.insert(
                    clap::error::ContextKind::InvalidArg,
                    clap::error::ContextValue::String(arg.to_string()),
                );
            }
            error.insert(
                clap::error::ContextKind::InvalidValue,
                clap::error::ContextValue::String(value.to_string()),
            );
            error
        })
    }

    fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {

View on GitHub (pinned to 26f38c119c)