rust-lang/cargo · error · anyhow::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 merging Cargo's ignore entries into an existing .gitignore/.hgignore/.ignore during `cargo new`/`cargo init`, IgnoreList::format_existing reads the file line-by-line as UTF-8. If a byte sequence is not valid UTF-8, the BufRead returns ErrorKind::InvalidData and Cargo surfaces this message naming the offending line number. Cargo only writes/manages UTF-8 ignore files.

Source

Thrown at src/ops/cargo_new.rs:660

            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 0e07a15537)

Solutions

  1. Re-encode the offending ignore file to UTF-8: `iconv -f LATIN1 -t UTF-8 .gitignore -o .gitignore`
  2. Open the file in an editor, fix or remove the invalid characters, and save as UTF-8
  3. Delete the ignore file and let Cargo regenerate it from scratch

Example fix

# before: .gitignore contains non-UTF-8 bytes -> error
# 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::path::Path;
fn ensure_ignore_utf8(path: &Path) -> Result<(), String> {
    let bytes = std::fs::read(path).map_err(|e| e.to_string())?;
    std::str::from_utf8(&bytes).map(|_| ()).map_err(|_| format!("{} is not valid UTF-8", path.display()))
}

for f in [".gitignore", ".hgignore", ".ignore"] { ensure_ignore_utf8(Path::new(f))?; }

Type guard

import { readFileSync } from 'fs';
function isValidUtf8(path: string): boolean {
  try { new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(path)); return true; }
  catch { return false; }
}

Prevention

When it happens

Trigger: `cargo init` (or `cargo new` into a dir) where the existing `.gitignore`/`.hgignore`/`.ignore` contains non-UTF-8 bytes - e.g. Latin-1 accented characters, a stray binary blob, or a file written by a tool that used the system codepage.

Common situations: Checkouts on Windows where the editor saved .gitignore as UTF-16 or with BOM+CRLF corruption; copy-pasted ignore content from a non-UTF-8 source; files touched by a misbehaving sed/iconv; legacy repos with mojibake.

Related errors


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