gitbutlerapp/gitbutler · error · anyhow::Error

'{src}' is not a directory

Error message

'{src}' is not a directory

What it means

`create_zip_file_from_dir()` in but-feedback requires `src_dir` to be an existing directory (it walks it with WalkDir to build the zip). A simple `is_dir()` check bails with the offending path when the source is missing or is a file. Note the message formats `src_dir.display()` while the guard itself is on `src_dir` — the path shown is the input directory path.

Source

Thrown at crates/but-feedback/src/zip.rs:21

    io::{self, Read, Write},
    path,
    path::{Path, PathBuf},
};

use anyhow::{Result, bail};
use walkdir::{DirEntry, WalkDir};
use zip::{CompressionMethod, ZipWriter, write::SimpleFileOptions};

/// Create a zip file from the *contents* of `src_dir` and write the zip file out to `dst_file`,
/// possibly overwriting it if it exists.
pub fn create_zip_file_from_dir(
    src_dir: impl AsRef<Path>,
    dst_file: impl AsRef<Path>,
) -> anyhow::Result<PathBuf> {
    let src_dir = src_dir.as_ref();
    let dst_file = dst_file.as_ref();
    if !src_dir.is_dir() {
        bail!("'{src}' is not a directory", src = src_dir.display());
    }

    let file = fs::File::create(dst_file)?;
    zip_dir(
        &mut WalkDir::new(src_dir).into_iter().filter_map(Result::ok),
        src_dir,
        file,
    )?;

    Ok(dst_file.to_owned())
}

/// Create a zip file with `src` content in a single-file archive, with the file named `src_file_name`,
/// and write the zip file out to `dst_file`, possibly overwriting it if it exists.
pub fn create_zip_file_from_content(
    src: &str,
    src_file_name: &str,
    dst_file: impl AsRef<Path>,

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Verify the path before calling: assert it exists and is a directory; print the canonical path on failure.
  2. Create the logs directory eagerly at application startup so it always exists by feedback time.
  3. Fix the configured path (trailing file component, wrong separator, env var empty).
  4. If the source may legitimately be absent, skip zip creation and report 'nothing to attach' instead.

Example fix

// before
let zip = but_feedback::zip::create_zip_file_from_dir(&maybe_wrong, &out)?;

// after
let dir = maybe_wrong.canonicalize().with_context(|| maybe_wrong.display().to_string())?;
anyhow::ensure!(dir.is_dir(), "{dir:?} is not a directory");
let zip = but_feedback::zip::create_zip_file_from_dir(&dir, &out)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust — validate the source directory before zipping
let src = src_dir.as_ref();
if !src.is_dir() {
    anyhow::bail!(
        "log directory '{}' is missing; nothing to attach",
        src.display()
    );
}
let zip = but_feedback::zip::create_zip_file_from_dir(src, dst)?;

Type guard

fn is_zip_source_dir(p: &std::path::Path) -> bool {
    p.is_dir()
}

Prevention

When it happens

Trigger: Calling feedback/log-zip creation with a path that doesn't exist, points to a regular file, or to a directory the process can't stat (permission-denied mount); race where the directory is deleted between composing the path and calling.

Common situations: Feedback bundle requested before logs directory was created; path built from a config value that's wrong (typo, wrong platform separator); containerized runs where the logs dir isn't mounted.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/a1e42b98f4e36a3a. Report an issue: GitHub.