GitoxideLabs/gitoxide · error

shell assignment names contain only ASCII bytes

Error message

shell assignment names contain only ASCII bytes

What it means

After an assignment separator is found, the variable NAME portion is decoded as UTF-8 and the code asserts shell assignment names are pure ASCII. A non-UTF8/ASCII byte in the assignment name (e.g. from odd shell quoting or binary content before `=`) panics instead of producing an error.

Solutions

  1. Ensure environment variable names in the command string are ASCII (standard for POSIX shells anyway)
  2. Sanitize or validate the command string bytes before parsing
  3. Handle it upstream: split assignments yourself and pass env explicitly via Outcome/env APIs
  4. File a bug requesting a graceful error instead of a panic for non-ASCII names

Example fix

// before
String::from_utf8(word.value[..separator].to_owned())
    .expect("shell assignment names contain only ASCII bytes")
// after
String::from_utf8(word.value[..separator].to_owned())
    .map_err(|_| Error::InvalidAssignmentName)?
Defensive patterns

Strategy: validation

Validate before calling

// Ensure assignment names are ASCII before parsing:
fn ascii_names_ok(cmd: &[u8]) -> bool {
    cmd.split(|b| *b == b'=').next()
        .map(|name| name.is_ascii() && !name.is_empty())
        .unwrap_or(false)
}

Type guard

fn is_ascii_name(name: &[u8]) -> bool { !name.is_empty() && name.iter().all(|b| b.is_ascii_alphanumeric() || *b == b'_') }

Prevention

When it happens

Trigger: Parsing a command line whose environment assignment name (the text before `=`) contains non-ASCII or invalid UTF-8 bytes, e.g. `VÄR=1 cmd` passed as raw bytes.

Common situations: Locale/encoding mismatches when building command strings on non-UTF8 filesystems; scripts embedding non-ASCII variable names; byte-level manipulation of command strings.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/47bb6d5862d03e88. Report an issue: GitHub.

Appendix: source

Thrown at gix-command/src/parse.rs:78

/// expansions and operators are not interpreted. An assignment is recognized only when its name is an unquoted
/// shell identifier. Assignment-only input is rejected because it contains no command to execute. Environment
/// assignment names are strings, while their values, the command, and arguments are converted losslessly to OS
/// strings or rejected if the platform cannot represent them.
pub fn command_line(input: &BStr) -> Result<Outcome, Error> {
    let mut words = parse_words(input)?;
    let assignment_count = words
        .iter()
        .take_while(|word| word.assignment_separator.is_some())
        .count();
    let mut args = words.split_off(assignment_count).into_iter().map(|word| word.value);
    let command = into_os_string(args.next().ok_or(Error::MissingCommand)?)?;
    let env = words
        .into_iter()
        .map(|word| {
            let separator = word.assignment_separator.expect("only recognized assignments remain");
            Ok((
                String::from_utf8(word.value[..separator].to_owned())
                    .expect("shell assignment names contain only ASCII bytes"),
                into_os_string(word.value[separator + 1..].to_owned().into())?,
            ))
        })
        .collect::<Result<_, Error>>()?;
    Ok(Outcome {
        env,
        command,
        args: args.map(into_os_string).collect::<Result<_, _>>()?,
    })
}

pub(crate) fn arguments(input: &BStr) -> Result<Vec<OsString>, Error> {
    parse_words(input)?
        .into_iter()
        .map(|word| into_os_string(word.value))
        .collect()
}

View on GitHub (pinned to e73179060b)