rust-lang/cargo · error

must be utf-8 in toml

Error message

must be utf-8 in toml

What it means

This panic is in BuildTargetConfig::values(), which resolves build.target config entries. When a target string ends with .json (a custom target spec file path), cargo joins the config definition root with the path and calls .to_str().expect("must be utf-8 in toml"). The invariant is that since the value originated from a TOML string (always UTF-8) and the cwd/root is also expected to be UTF-8, the joined path should be UTF-8.

Source

Thrown at src/context/schema.rs:288

            .string(|one| Ok(BuildTargetConfigInner::One(one.to_owned())))
            .seq(|many| many.deserialize().map(BuildTargetConfigInner::Many))
            .deserialize(deserializer)
    }
}

impl BuildTargetConfig {
    /// Gets values of `build.target` as a list of strings.
    pub fn values(&self, cwd: &Path) -> CargoResult<Vec<String>> {
        let map = |s: &String| {
            if s.ends_with(".json") {
                // Path to a target specification file (in JSON).
                // <https://doc.rust-lang.org/rustc/targets/custom.html>
                self.inner
                    .definition
                    .root(cwd)
                    .join(s)
                    .to_str()
                    .expect("must be utf-8 in toml")
                    .to_string()
            } else {
                // A string. Probably a target triple.
                s.to_string()
            }
        };
        let values = match &self.inner.val {
            BuildTargetConfigInner::One(s) => vec![map(s)],
            BuildTargetConfigInner::Many(v) => v.iter().map(map).collect(),
        };
        Ok(values)
    }
}

/// The `[resolver]` table.
///
/// Example configuration:
///

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Use an absolute path for the .json target spec file to avoid joining with a non-UTF-8 cwd.
  2. Ensure the working directory and all ancestor paths are valid UTF-8.
  3. Set locale environment variables (LANG, LC_ALL) to a UTF-8 encoding like en_US.UTF-8.

Example fix

// before
.join(s).to_str().expect("must be utf-8 in toml").to_string()
// after
.join(s).to_str().map(|s| s.to_string())
    .ok_or_else(|| anyhow::format_err!("build.target path `{}` is not valid UTF-8", s))?
Defensive patterns

Strategy: validation

Validate before calling

// Ensure cwd is UTF-8 before building with build.target = "*.json"
let cwd = std::env::current_dir()?;
if cwd.to_str().is_none() {
    return Err("working directory is not valid UTF-8; build.target .json paths may fail".into());
}

Type guard

fn is_utf8_path(path: &std::path::Path) -> bool {
    path.to_str().is_some()
}

Prevention

When it happens

Trigger: Setting build.target to a .json path in config while the working directory or config file location contains non-UTF-8 bytes (e.g., on Linux with a non-UTF-8 locale or a directory name with invalid byte sequences). The path join introduces the non-UTF-8 component.

Common situations: Running cargo on a system with a non-UTF-8 locale (LC_ALL, LANG set to legacy encodings); a project directory path containing non-UTF-8 characters; referencing a target spec JSON file via a relative path that traverses a non-UTF-8 directory.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/12d1ae467f4a0dbc.json. Report an issue: GitHub.