rust-lang/cargo · error

cannot package a filename with a special character

Error message

cannot package a filename with a special character `{}`: {}

What it means

Thrown by `check_filename` during `cargo package` when a filename contains one of the reserved special characters: `/ \ < > : " | ? *`. These characters are invalid in Windows filenames and would make the package fail to extract on that platform.

Solutions

  1. Rename the file to remove the special character.
  2. Remove the file from the source tree.
  3. Add the file path to the `exclude` list in Cargo.toml `[package]` section.

Example fix

# Rename the offending file
mv "log:2024.txt" log-2024.txt
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn check_filenames_no_special_chars(root: &Path) -> Result<(), String> {
    let bad = ['/', '\\', '<', '>', ':', '"', '|', '?', '*'];
    for entry in walkdir::WalkDir::new(root) {
        let entry = entry.map_err(|e| e.to_string())?;
        if let Some(name) = entry.file_name().to_str() {
            if let Some(c) = bad.iter().find(|c| name.contains(**c)) {
                return Err(format!("filename `{}` contains special char `{}`", name, c));
            }
        }
    }
    Ok(())
}

Prevention

When it happens

Trigger: Running `cargo package` when any file in the source tree contains one of `/'\<>:\"|?*` in its name. The check iterates `bad_chars` and bails on the first match.

Common situations: Files with colons in names (common in Unix backup tools like `2024-01-01:backup`); files with quotes or angle brackets created by other tooling; accidentally committed log files with timestamps containing colons.

Related errors


AI-assisted analysis of rust-lang/cargo@495c385d08 (2026-08-11). Data as JSON: /api/errors/796241603d5ef5c3. Report an issue: GitHub.

Appendix: source

Thrown at src/ops/cargo_package/mod.rs:1106

// can't actually be created on another platform. For example files with colons
// in the name are allowed on Unix but not on Windows.
//
// To help out in situations like this, issue about weird filenames when
// packaging as a "heads up" that something may not work on other platforms.
fn check_filename(file: &Path, shell: &mut Shell) -> CargoResult<()> {
    let Some(name) = file.file_name() else {
        return Ok(());
    };
    let Some(name) = name.to_str() else {
        anyhow::bail!(
            "path does not have a unicode filename which may not unpack \
             on all platforms: {}",
            file.display()
        )
    };
    let bad_chars = ['/', '\\', '<', '>', ':', '"', '|', '?', '*'];
    if let Some(c) = bad_chars.iter().find(|c| name.contains(**c)) {
        anyhow::bail!(
            "cannot package a filename with a special character `{}`: {}",
            c,
            file.display()
        )
    }
    if restricted_names::is_windows_reserved_path(file) {
        shell.warn(format!(
            "file {} is a reserved Windows filename, \
                it will not work on Windows platforms",
            file.display()
        ))?;
    }
    Ok(())
}

/// Manages a temporary local registry that we use to overlay our new packages on the
/// upstream registry. This way we can build lockfiles that depend on the new packages even
/// before they're published.

View on GitHub (pinned to 495c385d08)