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

the `.exe` extension is not allowed for directory names

Error message

the `.exe` extension is not allowed for directory names

What it means

This is a compile-time error from the layout! proc macro. Within a layout! declaration, the `[.exe]` suffix marks an entry whose on-disk name is `name` on Windows and `name.exe` elsewhere; a directory whose name literally ends in `.exe` (or `[.exe]`) is therefore rejected, since Volta's layout models executables, not directories, with those names. The macro emits a syn compile error pointing at the offending string literal.

Solutions

  1. Remove the ".exe" / "[.exe]" suffix from the directory's filename literal in the layout! block
  2. If a nested executable was intended, declare it as a file entry with the `[.exe]` suffix instead of a braced directory
  3. Rename the directory so its name does not end in .exe

Example fix

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

Strategy: validation

Validate before calling

fn valid_dir_name(name: &str) -> bool { !name.ends_with(".exe") && !name.ends_with("[.exe]") }
// check every directory literal in the layout! block before compiling

Try / catch

// proc-macro compile error: fix the source; no runtime catch applies.
// In CI, fail fast with: cargo check 2>&1 | grep 'not allowed for directory names'

Prevention

When it happens

Trigger: Declaring a directory entry in a layout! invocation whose filename literal ends with ".exe" or "[.exe]", e.g. `"tools/.exe": dir { ... }` or `"bin/tools[.exe]": dir { ... }`.

Common situations: Copy-pasting a Windows executable layout and mistakenly giving the directory the .exe name; confusing the `[.exe]` marker syntax (which belongs on executables) with directory entries; typos placing the marker on the wrong field.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

    /// Lowers the directory to a flattened intermediate representation.
    fn flatten(self, results: &mut Ir, context: Vec<LitStr>) -> Result<()> {
        let mut visited_entries = HashMap::new();

        for pair in self.entries.into_pairs() {
            let (prefix, punc) = pair.into_tuple();

            let mut entry = Entry {
                name: prefix.name,
                context: context.clone(),
                filename: prefix.filename.clone(),
            };

            match punc {
                Some(FieldContents::Dir(dir)) => {
                    let filename = prefix.filename.value();

                    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());
                    }

View on GitHub (pinned to 5eedd5fb2f)