volta-cli/volta · error · syn::Error

filename ` ` is a duplicate of ` ` executable on…

Error message

filename `{}` is a duplicate of `{}` executable on non-Windows operating systems

What it means

This is a compile-time error from the layout! proc macro: within one directory, every filename must be unique. The macro tracks each visited filename with an EntryKind; if a plain file or directory name collides with a name already declared as an `[.exe]` executable, it reports that the new filename is a duplicate of that executable (since on non-Windows the executable occupies the same `name`, and on Windows `name.exe`). A collision with a non-exe entry reports "duplicate filename".

Solutions

  1. Remove or rename the duplicate entry so each filename in the directory is unique
  2. If a platform-specific executable was intended, keep only the single `name[.exe]` entry and delete the plain-named one
  3. If both a file and executable with the same name are needed, they must live in different directories

Example fix

// before
"bin": dir { "node[.exe]": file; "node": file; }
// after
"bin": dir { "node[.exe]": file; }
Defensive patterns

Strategy: validation

Validate before calling

fn find_dup(names: &[&str]) -> Option<&str> {
    let mut seen = std::collections::HashSet::new();
    names.iter().find(|n| !seen.insert(strip_exe_marker(n)))
}
fn strip_exe_marker(n: &str) -> &str { n.strip_suffix("[.exe]").unwrap_or(n) }

Try / catch

// compile-time proc-macro error: no runtime catch. Pre-check literals for duplicates
// (after stripping [.exe]) before committing layout! changes; cargo check in CI.

Prevention

When it happens

Trigger: Declaring two entries with the same filename literal inside one layout! directory — specifically a file or dir entry whose name equals a previously declared `name[.exe]` executable entry, or any two entries sharing a name.

Common situations: Declaring both "node" and "node[.exe]" in the same directory; copy-pasting an entry and forgetting to rename it; merging layout blocks so the same tool is declared twice.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of volta-cli/volta@5eedd5fb2f (2026-09-08). Data as JSON: /api/errors/0ae06de5c607c451. Report an issue: GitHub.

Appendix: source

Thrown at crates/volta-layout-macro/src/ast.rs:162

                    if filename.ends_with(".exe") || filename.ends_with("[.exe]") {
                        let error = syn::Error::new(
                            prefix.filename.span(),
                            "the `.exe` extension is not allowed for directory names",
                        );
                        return Err(error.to_compile_error());
                    }

                    if let Some(kind) = visited_entries.get(&filename) {
                        let message = match kind {
                            EntryKind::Exe => {
                                format!("filename `{}` is a duplicate of `{}` executable on non-Windows operating systems", filename, filename)
                            }
                            _ => {
                                format!("duplicate filename `{}`", filename)
                            }
                        };
                        let error = syn::Error::new(prefix.filename.span(), message);
                        return Err(error.to_compile_error());
                    }

                    visited_entries.insert(filename.clone(), EntryKind::Dir);

                    results.dirs.push(entry);
                    let mut sub_context = context.clone();
                    sub_context.push(prefix.filename);
                    dir.flatten(results, sub_context)?;
                }
                _ => {
                    let filename = prefix.filename.value();
                    if filename.ends_with("[.exe]") {
                        let filename = &filename[0..filename.len() - 6];

                        if let Some(kind) = visited_entries.get(filename) {
                            let message = match kind {
                                EntryKind::Exe => {

View on GitHub (pinned to 5eedd5fb2f)