rustfs/rustfs · error · io::Error
rename base directory contains an invalid path component
Error message
rename base directory contains an invalid path component
What it means
Windows branch of mkdir_all_below_existing_base_std: while opening each component of base_dir relative to the publication root, any component that is not Normal (and not CurDir, which is skipped) — i.e. '..' or a root marker — is rejected with ErrorKind::InvalidInput. The base directory must be reachable purely through normal name components below the publication root so the chain of open directory handles cannot walk outside it.
Source
Thrown at crates/ecstore/src/disk/os.rs:2720
{
use windows_sys::Wdk::Storage::FileSystem::{FILE_OPEN, FILE_OPEN_IF};
use windows_sys::Win32::Storage::FileSystem::{FILE_SHARE_READ, FILE_SHARE_WRITE};
let base_relative = publication_root.relative_path(base_dir)?;
let capacity = base_relative
.components()
.count()
.saturating_add(relative.components().count())
.saturating_add(1);
let mut handles = Vec::with_capacity(capacity);
handles.push(publication_root.directory.clone());
let mut guard = ExistingBaseDirectoryGuard::new(handles);
for component in base_relative.components() {
let Component::Normal(component) = component else {
if matches!(component, Component::CurDir) {
continue;
}
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"rename base directory contains an invalid path component",
));
};
let parent = guard
.handles
.last()
.ok_or_else(|| io::Error::other("Windows publication root guard is empty"))?;
let child = open_windows_directory_component(parent, component, FILE_OPEN)?;
guard.handles.push(child);
}
for component in relative.components() {
let Component::Normal(component) = component else {
continue;
};
let parent = guard
.handles
.last()View on GitHub (pinned to 9e6e02ea09)
Solutions
- Normalize base_dir before the call and assert it starts with the publication root prefix
- Audit how publication_root and the bucket base directories are joined at startup; fix the mismatched join
- Add a Windows unit test pinning the exact path shapes for base vs publication root
Example fix
// before let base = Path::new(r"C:\rustfs\bucket"); // contains a root component vs publication root // after let base = publication_root.join(volume); // purely Normal components below the root
Defensive patterns
Strategy: validation
Validate before calling
// before renaming on Windows, base must be purely Normal components below the root
let ok = base_dir.strip_prefix(publication_root).map(|rel| {
rel.components().all(|c| matches!(c, std::path::Component::Normal(_) | std::path::Component::CurDir))
}).unwrap_or(false);
if !ok { return Err(/* fix base construction */); } Try / catch
Match ErrorKind::InvalidInput with the 'base directory contains an invalid path component' message; normalize base_dir and fix the join against publication_root — not retryable.
Prevention
- Normalize all storage paths at startup and assert the publication-root prefix relation
- Never mix absolute roots or '\\?\' style paths into base_dir construction
When it happens
Trigger: Windows rename publication where base_dir contains '..' or an absolute/root component relative to publication_root: volume roots like 'C:\' leaking into the joined path, unnormalized '\\?\' style paths, or a publication root configured at a different location than the base assumes.
Common situations: Deployments where the publication root and bucket directories are joined inconsistently at startup, path normalization changes during ports to Windows, or custom volume layouts.
Related errors
- rename source must have a file name
- rename destination must remain below its base directory
- rename destination contains an invalid path component
- rename destination parent must have a name
- InvalidInput
AI-assisted analysis of rustfs/rustfs@9e6e02ea09 (2026-08-16).
Data as JSON: /api/errors/d22c15733b0a2fca.
Report an issue: GitHub.