zed-industries/zed · error · anyhow::Error
extension {extension_id} is still installed
Error message
extension {extension_id} is still installed What it means
install_dev_extension installs a local extension by symlinking extensions/installed/<id> to your source directory. If the target path already exists as a real directory (not a symlink) — i.e. a marketplace-installed extension occupies that slot — it bails rather than destructively removing a real install; only a leftover symlink is auto-removed.
Source
Thrown at crates/extension_host/src/extension_host.rs:1113
cx: &mut Context<Self>,
) -> Task<Result<()>> {
let extensions_dir = self.extensions_dir();
let fs = self.fs.clone();
let builder = self.builder.clone();
cx.spawn(async move |this, cx| {
let mut extension_manifest =
ExtensionManifest::load(fs.clone(), &extension_source_path).await?;
let extension_id = extension_manifest.id.clone();
if let Some(uninstall_task) = this
.update(cx, |this, cx| {
this.extension_index
.extensions
.get(extension_id.as_ref())
.is_some_and(|index_entry| !index_entry.dev)
.then(|| this.uninstall_extension(extension_id.clone(), cx))
})
.ok()
.flatten()
{
uninstall_task.await.log_err();
}
if !this.update(cx, |this, cx| {
match this.outstanding_operations.entry(extension_id.clone()) {
btree_map::Entry::Occupied(_) => return false,
btree_map::Entry::Vacant(e) => e.insert(ExtensionOperation::Install),
};
cx.notify();
true
})? {
return Ok(());
}
let _finish = cx.on_drop(&this, {View on GitHub (pinned to 9d272b0363)
Solutions
- Uninstall the marketplace version first via the Extensions page in Zed.
- Or manually remove the directory: rm -rf ~/.local/share/zed/extensions/installed/<extension-id> (macOS: ~/Library/Application Support/Zed/...).
- Then re-run Install Dev Extension — the fresh symlink will be created.
Example fix
# before: marketplace copy occupies the slot rm -rf ~/.local/share/zed/extensions/installed/my-extension # then in Zed:Extensions page # after: "Install Dev Extension" now symlinks your local source ln -s ~/src/my-extension ~/.local/share/zed/extensions/installed/my-extension # what Zed does for you
Defensive patterns
Strategy: validation
Validate before calling
let output_path = extensions_dir.join(extension_id.as_ref());
if let Some(metadata) = fs.metadata(&output_path).await? {
if !metadata.is_symlink {
// a real (marketplace) install occupies the slot — uninstall it first
store.uninstall_extension(extension_id.clone(), cx)?.await?;
}
}
// safe to create the dev-extension symlink now Try / catch
match fs.metadata(&output_path).await {
Ok(metadata) if !metadata.is_symlink => {
// bail path: tell the user to uninstall the marketplace version first
}
Ok(_) => { /* symlink or absent: proceed */ }
Err(e) if e.io_error_kind() == io::ErrorKind::NotFound => { /* proceed */ }
Err(e) => return Err(e.into()),
} Prevention
- Uninstall the marketplace version before iterating on a local fork of the same extension id.
- Treat install_dev_extension failures mentioning 'still installed' as a prompt to clean extensions/installed/<id>.
- In automation, pre-clean the extensions directory before installing dev extensions.
When it happens
Trigger: Using the Install Dev Extension command (or extensions_ui install_dev_extension) for an extension id that is currently installed from the marketplace, so extensions/installed/<id> is a regular directory.
Common situations: Iterating on a fork of an extension you already installed normally; CI machines with a pre-seeded extensions directory; switching between the published version and a local checkout.
Related errors
- extension dir {} is not an absolute path
- failed to compile {} parser with clang: {}
- grammar directory '{}' already exists, but is not a git clon
- failed to run `git init` in directory '{}'
- unsupported architecture {unsupported}
AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20).
Data as JSON: /api/errors/fd458318dbbc464e.
Report an issue: GitHub.