rust-lang/cargo · error
Character at line is invalid. Cargo only supports UTF-8.
Error message
Character at line {} is invalid. Cargo only supports UTF-8. What it means
While formatting/updating an existing VCS ignore file (`.gitignore`, `.hgignore`, etc.), cargo reads it line-by-line as UTF-8. If `BufRead::lines` returns `InvalidData` (the std `Utf8Error`-mapping for non-UTF-8 bytes), cargo surfaces it naming the offending line number. Cargo only handles UTF-8 content and refuses to round-trip binary/non-UTF-8 ignore files.
Solutions
- Re-save the ignore file as UTF-8 (`iconv -f LATIN1 -t UTF-8 .gitignore` or open and re-save in an editor set to UTF-8).
- Remove the offending non-UTF-8 bytes/lines (the error names the line number).
- Delete the ignore file and let cargo regenerate it, if its existing content is not worth keeping.
Example fix
# before — .gitignore contains non-UTF-8 bytes at line 12 $ cargo init # error: Character at line 12 is invalid. Cargo only supports UTF-8. # after $ iconv -f LATIN1 -t UTF-8 .gitignore -o .gitignore.utf8 && mv .gitignore.utf8 .gitignore $ cargo init
Defensive patterns
Strategy: validation
Validate before calling
use std::fs;
use std::str;
fn ignore_file_is_utf8(path: &std::path::Path) -> bool {
match fs::read(path) {
Ok(bytes) => str::from_utf8(&bytes).is_ok(),
Err(_) => false,
}
}
// before `cargo init`, re-encode the ignore file to UTF-8 if this returns false. Type guard
fn is_utf8_ignore_file(bytes: &[u8]) -> bool { std::str::from_utf8(bytes).is_ok() } Prevention
- Keep `.gitignore`/`.hgignore` as UTF-8; re-encode legacy files before `cargo init`.
- Avoid tools that emit non-UTF-8 into ignore files.
- In scaffolding, validate ignore-file encoding and convert before invoking cargo.
- Add ignore-file health checks to repo onboarding scripts.
When it happens
Trigger: `cargo init` (or `cargo new` with VCS) in a directory whose existing `.gitignore`/`.hgignore`/`.fossil-ignore` contains non-UTF-8 bytes (e.g. a stray binary blob, latin-1 encoded content, or a corrupted file). The error fires in `format_existing` during the ignore-list merge.
Common situations: A pre-existing `.gitignore` written by a tool that emitted non-UTF-8 (e.g. Windows-1252 on some legacy systems). Corruption from a bad merge or file transfer. A `.gitignore` that accidentally swallowed binary content.
Related errors
- more than one of .hg, .git, .pijul, .fossil configurations…
- {}: {:?}
- ` ` resolved to non-UTF value (` `)
- argument for argfile contains invalid UTF-8 characters
- cannot create package in the home directory help: use…
AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11).
Data as JSON: /api/errors/298f41657629dfcf.
Report an issue: GitHub.
Appendix: source
Thrown at src/ops/cargo_new.rs:609
VersionControl::Fossil => &self.fossil_ignore,
_ => &self.ignore,
};
ignore_items.join("\n") + "\n"
}
/// `format_existing` is used to format the `IgnoreList` when the ignore file
/// already exists. It reads the contents of the given `BufRead` and
/// checks if the contents of the ignore list are already existing in the
/// file.
fn format_existing<T: BufRead>(&self, existing: T, vcs: VersionControl) -> CargoResult<String> {
let mut existing_items = Vec::new();
for (i, item) in existing.lines().enumerate() {
match item {
Ok(s) => existing_items.push(s),
Err(err) => match err.kind() {
ErrorKind::InvalidData => {
return Err(anyhow!(
"Character at line {} is invalid. Cargo only supports UTF-8.",
i
));
}
_ => return Err(anyhow!(err)),
},
}
}
let ignore_items = match vcs {
VersionControl::Hg => &self.hg_ignore,
VersionControl::Fossil => &self.fossil_ignore,
_ => &self.ignore,
};
let mut out = String::new();
// Fossil does not support `#` comments.View on GitHub (pinned to 98a09e7e7d)