{"record":{"id":"fd458318dbbc464e","repo":"zed-industries/zed","slug":"extension-extension-id-is-still-installed","errorCode":null,"errorMessage":"extension {extension_id} is still installed","messagePattern":"extension (.+?) is still installed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/extension_host/src/extension_host.rs","lineNumber":1113,"sourceCode":"        cx: &mut Context<Self>,\n    ) -> Task<Result<()>> {\n        let extensions_dir = self.extensions_dir();\n        let fs = self.fs.clone();\n        let builder = self.builder.clone();\n\n        cx.spawn(async move |this, cx| {\n            let mut extension_manifest =\n                ExtensionManifest::load(fs.clone(), &extension_source_path).await?;\n            let extension_id = extension_manifest.id.clone();\n\n            if let Some(uninstall_task) = this\n                .update(cx, |this, cx| {\n                    this.extension_index\n                        .extensions\n                        .get(extension_id.as_ref())\n                        .is_some_and(|index_entry| !index_entry.dev)\n                        .then(|| this.uninstall_extension(extension_id.clone(), cx))\n                })\n                .ok()\n                .flatten()\n            {\n                uninstall_task.await.log_err();\n            }\n\n            if !this.update(cx, |this, cx| {\n                match this.outstanding_operations.entry(extension_id.clone()) {\n                    btree_map::Entry::Occupied(_) => return false,\n                    btree_map::Entry::Vacant(e) => e.insert(ExtensionOperation::Install),\n                };\n                cx.notify();\n                true\n            })? {\n                return Ok(());\n            }\n\n            let _finish = cx.on_drop(&this, {","sourceCodeStart":1095,"sourceCodeEnd":1131,"githubUrl":"https://github.com/zed-industries/zed/blob/9d272b036335401f339d024ea94968fd51016c40/crates/extension_host/src/extension_host.rs#L1095-L1131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before: marketplace copy occupies the slot\nrm -rf ~/.local/share/zed/extensions/installed/my-extension\n# then in Zed:Extensions page\n# after: \"Install Dev Extension\" now symlinks your local source\nln -s ~/src/my-extension ~/.local/share/zed/extensions/installed/my-extension  # what Zed does for you","handlingStrategy":"validation","validationCode":"let output_path = extensions_dir.join(extension_id.as_ref());\nif let Some(metadata) = fs.metadata(&output_path).await? {\n    if !metadata.is_symlink {\n        // a real (marketplace) install occupies the slot — uninstall it first\n        store.uninstall_extension(extension_id.clone(), cx)?.await?;\n    }\n}\n// safe to create the dev-extension symlink now","typeGuard":null,"tryCatchPattern":"match fs.metadata(&output_path).await {\n    Ok(metadata) if !metadata.is_symlink => {\n        // bail path: tell the user to uninstall the marketplace version first\n    }\n    Ok(_) => { /* symlink or absent: proceed */ }\n    Err(e) if e.io_error_kind() == io::ErrorKind::NotFound => { /* proceed */ }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["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."],"tags":["extension","install","dev-extension","symlink","conflict"],"backgroundTag":"install-path-conflict","analyzedSha":"9d272b036335401f339d024ea94968fd51016c40","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}