rust-lang/cargo · error

local registry path is not a directory

Error message

local registry path is not a directory: {}

What it means

A local registry (`registry = "file://..."` style source) requires its root directory to exist on disk. During `update()`, Cargo checks `root.is_dir()`; if the path is missing or is a file, it bails. Local registries serve pre-populated index + `.crate` files from the filesystem (no network), so the directory must exist.

Solutions

  1. Verify the path exists and is a directory: `ls -la <path>`.
  2. Fix the configured path in `.cargo/config.toml` / `Cargo.toml` to the correct absolute location.
  3. Populate the local registry (vendor the index and `.crate` files) before building.
  4. Use an absolute path to avoid working-directory ambiguity.

Example fix

# before
[source.mylocal]
registry = "file:///opt/cargo-registry"   # missing

# after
[source.mylocal]
registry = "file:///srv/cargo-registry"   # exists and is a dir
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_local_registry_root(root: &Path) -> Result<(), anyhow::Error> {
    if !root.is_dir() { anyhow::bail!("local registry root is not a directory: {}", root.display()); }
    Ok(())
}

Type guard

fn local_registry_root_exists(root: &std::path::Path) -> bool { root.is_dir() }

Try / catch

if !root.is_dir() {
    // attempt to mount/populate, else surface actionable message
    return Err(anyhow!("local registry path missing: {}; vendor or fix config", root.display()));
}

Prevention

When it happens

Trigger: A `[source.<name>]` or dependency configured with `registry =` pointing at a local filesystem path that does not exist or is not a directory. Reached on the first `update()` of a `LocalRegistry`.

Common situations: Path moved/renamed since config was written; relative path interpreted from a different working directory; local registry never vendored into place; typo in the `file://` URL; build server missing the mounted registry volume.

Related errors


AI-assisted analysis of rust-lang/cargo@eb98b54bc9 (2026-08-11). Data as JSON: /api/errors/32573c3e648ec587. Report an issue: GitHub.

Appendix: source

Thrown at src/sources/registry/local.rs:97

            src_path: gctx.registry_source_path().join(name),
            index_path: Filesystem::new(root.join("index")),
            root: Filesystem::new(root.to_path_buf()),
            gctx,
            updated: Cell::new(false),
            quiet: false,
        }
    }

    fn update(&self) -> CargoResult<()> {
        if self.updated.get() {
            return Ok(());
        }
        // Nothing to update, we just use what's on disk. Verify it actually
        // exists though. We don't use any locks as we're just checking whether
        // these directories exist.
        let root = self.root.clone().into_path_unlocked();
        if !root.is_dir() {
            anyhow::bail!("local registry path is not a directory: {}", root.display());
        }
        let index_path = self.index_path.clone().into_path_unlocked();
        if !index_path.is_dir() {
            anyhow::bail!(
                "local registry index path is not a directory: {}",
                index_path.display()
            );
        }
        self.updated.set(true);
        Ok(())
    }
}

#[async_trait::async_trait(?Send)]
impl<'gctx> RegistryData for LocalRegistry<'gctx> {
    fn prepare(&self) -> CargoResult<()> {
        Ok(())
    }

View on GitHub (pinned to eb98b54bc9)