GitoxideLabs/gitoxide · error

Cannot derive archive format from a file without extension

Error message

Cannot derive archive format from a file without extension

What it means

`format_from_ext` derives the archive format from the output filename's extension. If the path has no extension at all, no format can be inferred and the function bails. gitoxide does not guess archive formats from content.

Solutions

  1. Rename the output file to include a supported extension (.tar, .gz, .zip, .stream)
  2. Use `.tar` explicitly when a plain uncompressed archive is wanted
  3. Generate the filename programmatically to always append a valid extension

Example fix

// before
let out = Path::new("archive-2024");
// after
let out = Path::new("archive-2024.tar");
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_supported_name(path: &Path) -> anyhow::Result<()> {
    let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
    anyhow::ensure!(matches!(ext, "tar" | "gz" | "zip" | "stream"), "output path needs a supported archive extension");
    Ok(())
}

Try / catch

match archive::stream(repo, rev, out, path_without_ext) {
    Err(e) if e.to_string().contains("without extension") => {
        // append ".tar" and retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `archive::stream` with an output path lacking a `.tar`/`.gz`/`.zip`/`.stream` extension - e.g. `out`, `archive.v1`, or a path whose final component has no dot.

Common situations: Writing to a named pipe or versioned filename without extension; deriving output names in scripts from commit ids; users expecting a default tar format.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/68e80fe7f505c799. Report an issue: GitHub.

Appendix: source

Thrown at gitoxide-core/src/repository/archive.rs:97

}

fn fetch_rev_info(
    object: gix::Object<'_>,
) -> anyhow::Result<(Option<gix::date::SecondsSinceUnixEpoch>, gix::ObjectId)> {
    Ok(match object.kind {
        gix::object::Kind::Commit => {
            let commit = object.into_commit();
            (Some(commit.committer()?.seconds()), commit.tree_id()?.detach())
        }
        gix::object::Kind::Tree => (None, object.id),
        gix::object::Kind::Tag => fetch_rev_info(object.peel_to_kind(gix::object::Kind::Commit)?)?,
        gix::object::Kind::Blob => bail!("Cannot derive commit or tree from blob at {}", object.id),
    })
}

fn format_from_ext(path: &Path) -> anyhow::Result<archive::Format> {
    Ok(match path.extension().and_then(std::ffi::OsStr::to_str) {
        None => bail!("Cannot derive archive format from a file without extension"),
        Some("tar") => archive::Format::Tar,
        Some("gz") => archive::Format::TarGz {
            compression_level: None,
        },
        Some("zip") => archive::Format::Zip {
            compression_level: None,
        },
        Some("stream") => archive::Format::InternalTransientNonPersistable,
        Some(ext) => bail!("Format for extension '{ext}' is unsupported"),
    })
}

View on GitHub (pinned to e73179060b)