rust-lang/cargo · error

local registry index path is not a directory

Error message

local registry index path is not a directory: {}

What it means

After validating the local registry root directory exists, Cargo also checks that the `<root>/index` subdirectory exists. If `index_path.is_dir()` is false, it bails. The index directory holds the crates.io-style index tree that a local registry must provide.

Solutions

  1. Inspect `<root>` and ensure an `index/` directory exists with the crates.io index layout.
  2. Re-vendor the local registry from source so both root and index are populated.
  3. Point the configuration at the correct registry root that contains `index/`.
  4. Consult the local registry format docs and rebuild the index tree.

Example fix

# before: root exists but index/ missing
$ ls /srv/cargo-registry
cache  config.json          # no index/

# after: vendor a proper local registry
$ ls /srv/cargo-registry
cache  config.json  index/
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_local_registry_index(root: &Path) -> Result<(), anyhow::Error> {
    let idx = root.join("index");
    if !idx.is_dir() { anyhow::bail!("local registry index missing: {}", idx.display()); }
    Ok(())
}

Type guard

fn local_registry_index_present(root: &std::path::Path) -> bool { root.join("index").is_dir() }

Try / catch

if !index_path.is_dir() {
    return Err(anyhow!("index dir missing; re-vendor local registry with index/ subtree"));
}

Prevention

When it happens

Trigger: Local registry root exists but the `<root>/index` subdirectory is missing or is a file. Reached immediately after the root check passes in `LocalRegistry::update()`.

Common situations: Partially-vendored local registry (root created but index omitted); wrong index layout; the `index` path replaced by a file; misconfigured `registries.<name>.index` pointing at a parent that lacks the standard `index/` child.

Related errors


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

Appendix: source

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

            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(())
    }

    fn index_path(&self) -> &Filesystem {
        &self.index_path
    }

View on GitHub (pinned to eb98b54bc9)