BigPizzaV3/CodexPlusPlus · warning

zip entry has empty path

Error message

zip entry has empty path

What it means

safe_zip_path (crates/codex-plus-core/src/plugin_marketplace.rs:453) rejects entry names that normalize to an empty relative path — e.g. the name '.', an empty string, or a run of only-current-dir components — after the escape check passes. An empty path has no file to write and would otherwise collapse into writing onto the destination directory itself, so extraction refuses it.

Source

Thrown at crates/codex-plus-core/src/plugin_marketplace.rs:453

            .with_context(|| format!("failed to read zip entry {}", file.name()))?;
        std::fs::write(&output_path, contents)
            .with_context(|| format!("failed to write {}", output_path.display()))?;
    }
    Ok(())
}

fn safe_zip_path(name: &str) -> anyhow::Result<PathBuf> {
    let path = Path::new(name);
    let mut relative = PathBuf::new();
    for component in path.components() {
        match component {
            Component::Normal(value) => relative.push(value),
            Component::CurDir => {}
            _ => anyhow::bail!("zip entry escapes destination: {name}"),
        }
    }
    if relative.as_os_str().is_empty() {
        anyhow::bail!("zip entry has empty path");
    }
    Ok(relative)
}

fn zip_entry_relative_path(name: &str) -> Option<PathBuf> {
    let path = Path::new(name);
    let mut components = path.components();
    match components.next()? {
        Component::Normal(_) => {}
        _ => return None,
    }
    let mut relative = PathBuf::new();
    for component in components {
        match component {
            Component::Normal(value) => relative.push(value),
            Component::CurDir => {}
            _ => return None,
        }

View on GitHub (pinned to 1f431ae49b)

Solutions

  1. Rebuild the zip without degenerate entries: list with `unzip -l` and repack excluding '.'/empty names
  2. Re-download the artifact from the official URL — empty-name entries often indicate corruption in transit
  3. If writing the zip programmatically, skip directory markers and empty names when adding entries (zipfile: skip when arcname in ('', '.'))
  4. Treat repeated occurrences as tampering and fall back to the embedded marketplace copy

Example fix

# python: before — accidentally adds empty-name entry
zf.writestr('', b'')

# after — skip degenerate names entirely
if name in ('', '.'):
    continue
zf.writestr(name, data)
Defensive patterns

Strategy: validation

Validate before calling

fn zip_names_valid(names: impl IntoIterator<Item = String>) -> bool {
    names.into_iter().all(|name| {
        let mut rel = std::path::PathBuf::new();
        for c in std::path::Path::new(&name).components() {
            match c {
                std::path::Component::Normal(v) => rel.push(v),
                std::path::Component::CurDir => {}
                _ => return false,
            }
        }
        !rel.as_os_str().is_empty()
    })
}

Type guard

fn entry_name_usable(name: &str) -> bool {
    !name.trim().is_empty() && name != "."
}

Try / catch

// Skip-and-continue for degenerate entries is acceptable when repacking your own artifacts;
// for downloads, fail the install
Err(e) if e.to_string() == "zip entry has empty path" => {
    tracing::warn!("archive contains empty-name entry; treating artifact as malformed");
    redownload_and_retry_once().await?
}

Prevention

When it happens

Trigger: Extracting a marketplace zip containing a directory entry named '.' or '' (or a sequence of '.' components) — typically produced by buggy archivers, hand-rolled zip writers, or deliberate malformed-archive fuzzing.

Common situations: Zips packed with a redundant './' prefix entry; archives created by scripts using zipfile with an accidental empty arcname; corrupted downloads where entry headers degrade to empty names.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16). Data as JSON: /api/errors/ec776213979574fa. Report an issue: GitHub.