tikv/tikv · error

the file name (it is {}) should not be empty

Error message

the file name (it is {}) should not be empty

What it means

LocalStorage::write rejects empty file names — either an empty string or a path whose final component is empty (e.g. "dir/" or "."). Such a name identifies no writable file, so it fails with io::ErrorKind::Unsupported before touching the filesystem.

Source

Thrown at components/external_storage/src/local.rs:106

    async fn write(
        &self,
        name: &str,
        reader: UnpinReader<'_>,
        _content_length: u64,
    ) -> io::Result<()> {
        let p = Path::new(name);
        if p.is_absolute() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!(
                    "the file name (it is {}) should never be absolute path",
                    p.display()
                ),
            ));
        }
        if name.is_empty() || p.file_name().map(|s| s.is_empty()).unwrap_or(true) {
            return Err(io::Error::new(
                io::ErrorKind::Unsupported,
                format!("the file name (it is {}) should not be empty", p.display()),
            ));
        }
        // create the parent dir if there isn't one.
        // note: we may write to arbitrary directory here if the path contains things
        // like '../' but internally the file name should be fully controlled by
        // TiKV, so maybe it is OK?
        if let Some(parent) = Path::new(name).parent() {
            fs::create_dir_all(self.base.join(parent))
                .await
                // According to the man page mkdir(2), it returns EEXIST if there is already the dir.
                // (However in practice, it doesn't fail in both Linux(CentOS 7) and macOS(12.2).)
                // Ignore the `AlreadyExists` anyway for safety.
                .or_else(|e| {
                    if e.kind() == io::ErrorKind::AlreadyExists {
                        Ok(())
                    } else {

View on GitHub (pinned to 78aedc1c81)

Solutions

  1. Validate the name is non-empty and has a real file_name() component before calling write.
  2. Fix upstream path construction so the basename is preserved after stripping prefixes.
  3. Use Path::file_name() to assert a concrete file component exists; reject directories.
  4. Check backup manifests/config for blank name fields and correct the producer.

Example fix

// before
let name = path.strip_prefix(&base).unwrap(); // may be "dir/"
storage.write(name.to_str().unwrap(), reader, len).await?;
// after
let name = path.strip_prefix(&base)?;
assert!(name.file_name().map(|f| !f.is_empty()).unwrap_or(false));
storage.write(name.to_str().unwrap(), reader, len).await?;
Defensive patterns

Strategy: validation

Validate before calling

// ensure a concrete file component exists before writing
fn has_file_name(name: &str) -> bool {
    Path::new(name).file_name().map(|f| !f.is_empty()).unwrap_or(false)
}

Type guard

fn is_writable_name(name: &str) -> bool {
    !name.is_empty() && Path::new(name).file_name().map(|f| !f.is_empty()).unwrap_or(false)
}

Try / catch

match storage.write(name, reader, len).await {
    Err(e) if e.kind() == io::ErrorKind::Unsupported => {
        // name empty or directory-like: fix name construction
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling LocalStorage::write/save_file with name = "", "dir/", ".", or any path whose file_name() component is empty or missing.

Common situations: String slicing/strip_prefix producing a trailing slash; format! or Path::join bugs leaving an empty basename; manifest entries with blank file names; automation generating paths from empty variables.

Related errors


AI-assisted analysis of tikv/tikv@78aedc1c81 (2026-09-03). Data as JSON: /api/errors/4cf1bee3f81bc6e5. Report an issue: GitHub.