rust-lang/cargo · error
argument for argfile contains invalid UTF-8 characters
Error message
argument for argfile contains invalid UTF-8 characters: `{}` What it means
In `ProcessBuilder::get_command_and_argfile` (cargo-util), Cargo serializes its arguments into a temporary argfile (one per line) when the argument list is large. Each `OsString` argument is converted to `&str` via `to_str()`; if any argument contains non-UTF-8 bytes the conversion fails and an `io::Error` (kind `Other`) is returned with the lossy rendering of the argument. The argfile format is line-delimited UTF-8 text, so non-UTF-8 arguments cannot be represented.
Solutions
- Ensure every argument passed to the `ProcessBuilder` is valid UTF-8 before triggering argfile creation.
- Sanitize or percent-encode any path argument that may carry non-UTF-8 bytes.
- Avoid deriving `ProcessBuilder` arguments from raw OS strings of unknown encoding.
Example fix
// before let arg: OsString = ...; // may contain non-UTF-8 bytes pb.arg(arg); // after: validate / sanitize first let arg = arg.into_string().map_err(|_| "non-utf8 arg")?; pb.arg(arg);
Defensive patterns
Strategy: validation
Validate before calling
use std::ffi::OsString;
fn args_all_utf8(args: &[OsString]) -> Result<(), String> {
for a in args {
a.to_str().ok_or_else(|| format!("non-utf8 arg: {:?}", a))?;
}
Ok(())
}
// call before constructing a ProcessBuilder that may trigger argfile mode Prevention
- Never feed raw non-UTF-8 OsStrings into ProcessBuilder args.
- Sanitize environment-derived paths before passing them as arguments.
- Unit-test subprocess invocations with UTF-8 assertions on every arg.
When it happens
Trigger: Building a `ProcessBuilder` whose `args` contain an `OsString` with non-UTF-8 bytes, then calling the method that materializes the argfile (used when command-line length limits force an argfile). Common with non-UTF-8 environment-derived paths or user-supplied arguments on Unix.
Common situations: Passing a file path argument that contains non-UTF-8 bytes (rare, but possible on Unix), or a crate/tool name generated from a non-UTF-8 source. Surfaces only when the argument count/size triggers argfile mode.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- argument for argfile contains newlines
- failed to parse process output
- Character at line is invalid. Cargo only supports UTF-8.
- credential process ` ` failed with status
- {}: {:?}
AI-assisted analysis of rust-lang/cargo@42eee92bc9 (2026-08-11).
Data as JSON: /api/errors/9f21dcbd698feed5.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cargo-util/src/process_builder.rs:504
/// arguments. This is primarily served for rustc/rustdoc command family.
fn build_command_with_argfile(&self) -> io::Result<(Command, NamedTempFile)> {
use std::io::Write as _;
let mut tmp = tempfile::Builder::new()
.prefix("cargo-argfile.")
.tempfile()?;
let mut arg = OsString::from("@");
arg.push(tmp.path());
let mut cmd = self.build_command_without_args();
cmd.arg(arg);
tracing::debug!("created argfile at {} for {self}", tmp.path().display());
let cap = self.get_args().map(|arg| arg.len() + 1).sum::<usize>();
let mut buf = Vec::with_capacity(cap);
for arg in &self.args {
let arg = arg.to_str().ok_or_else(|| {
io::Error::new(
io::ErrorKind::Other,
format!(
"argument for argfile contains invalid UTF-8 characters: `{}`",
arg.to_string_lossy()
),
)
})?;
if arg.contains('\n') {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("argument for argfile contains newlines: `{arg}`"),
));
}
writeln!(buf, "{arg}")?;
}
tmp.write_all(&mut buf)?;
Ok((cmd, tmp))
}View on GitHub (pinned to 42eee92bc9)