jdx/mise · error · eyre::Report

created path component

Error message

created path component {} was replaced before it could be opened

What it means

Mise creates a missing path component with O_CREAT|O_EXCL-style semantics and then fstat()s it. If the freshly created component's owner is not the current effective UID, the path was swapped out between creation and open — a classic TOCTOU attack — so mise refuses to open the replaced component it just created.

Solutions

  1. Re-run the mise command — transient races usually succeed on retry
  2. Ensure no concurrent user/process is manipulating the same path
  3. Make the parent directory owned by you and not writable by others (chmod go-w)

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

import os
def component_owned_by_me(path):
    return os.stat(path).st_uid == os.geteuid()

Try / catch

match result {
    Err(e) if e.to_string().contains("was replaced before it could be opened") => {
        // transient race: back off briefly and retry once
    }
    r => r,
}

Prevention

When it happens

Trigger: Another process (or attacker) replaces a component mise just created in a managed path before mise opens it; created_by_us is true and the fstat uid check fails.

Common situations: Two users sharing a directory where one races the other's mise operation; a tmpwatch/cleanup daemon deleting and recreating directories mid-run; malicious symlink-swapping in a writable parent.

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 jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/c98e067e03ffbb17. Report an issue: GitHub.

Appendix: source

Thrown at src/system/managed_files.rs:1735

                        return Err(error).wrap_err_with(|| {
                            format!(
                                "failed to create path component {}",
                                component_path.display()
                            )
                        });
                    }
                };
                let created = openat(&directory, name.as_os_str(), flags, Mode::empty())
                    .wrap_err_with(|| {
                        format!(
                            "failed to open newly available path component {} without following symlinks",
                            component_path.display()
                        )
                    })?;
                let stat = nix::sys::stat::fstat(&created)?;
                if stat.st_uid != nix::unistd::geteuid().as_raw() {
                    if created_by_us {
                        bail!(
                            "created path component {} was replaced before it could be opened",
                            component_path.display()
                        );
                    } else {
                        bail!(
                            "path component {} was concurrently created by another user",
                            component_path.display()
                        );
                    }
                }
                created
            }
        };
        current.push(name);
    }
    Ok(directory)
}

View on GitHub (pinned to 533346cc37)