zed-industries/zed · error · anyhow::Error
capability for npm:install {package_name} is not granted by
Error message
capability for npm:install {package_name} is not granted by the extension host What it means
The host gates npm package installation for WASM extensions through CapabilityGranter::grant_npm_install_package. An `npm:install` capability in the manifest must allow the exact package name (the pattern may only be the exact name or `*`). When the requested package is not granted, it bails naming the package.
Source
Thrown at crates/extension_host/src/capability_granter.rs:79
);
}
Ok(())
}
pub fn grant_npm_install_package(&self, package_name: &str) -> Result<()> {
let is_allowed = self
.granted_capabilities
.iter()
.any(|capability| match capability {
ExtensionCapability::NpmInstallPackage(capability) => {
capability.allows(package_name)
}
_ => false,
});
if !is_allowed {
bail!("capability for npm:install {package_name} is not granted by the extension host",);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use extension::{ProcessExecCapability, SchemaVersion};
use super::*;
fn extension_manifest() -> ExtensionManifest {
ExtensionManifest {
id: "test".into(),
name: "Test".to_string(),View on GitHub (pinned to f4178619ac)
Solutions
- Add an [[capabilities]] kind = "npm:install" entry whose `package` exactly equals the name in the error message.
- If the extension legitimately installs a fixed, known set of packages, list each one; only use package = "*" when every install is user-driven and trusted.
- Rebuild and re-test the extension so the manifest is re-read.
Example fix
# before [[capabilities]] kind = "npm:install" package = "tree-sitter-javascript" # after: also grant the newly added package [[capabilities]] kind = "npm:install" package = "tree-sitter-javascript" [[capabilities]] kind = "npm:install" package = "tree-sitter-typescript"
Defensive patterns
Strategy: validation
Validate before calling
fn npm_install_allowed(manifest: &ExtensionManifest, package_name: &str) -> bool {
manifest.capabilities.iter().any(|capability| match capability {
ExtensionCapability::NpmInstallPackage(capability) => capability.allows(package_name),
_ => false,
})
}
// before installing from extension code
assert!(npm_install_allowed(&manifest, "tree-sitter-typescript"),
"package lacks an npm:install capability"); Type guard
fn is_npm_install_capable(capability: &ExtensionCapability) -> bool {
matches!(capability, ExtensionCapability::NpmInstallPackage(_))
} Prevention
- Enumerate every package the extension can install and add one capability entry per exact name.
- Avoid dynamic package names unless they are fully user-supplied and covered by package = "*" deliberately.
- Unit-test the manifest against the set of packages referenced in code.
When it happens
Trigger: Extension code calls the npm install guest function for a package that has no matching [[capabilities]] kind = "npm:install" entry — e.g. version-suffixed names, scoped packages (@scope/name) added later, or dynamically chosen packages.
Common situations: Language extensions that lazily install grammars/tools per language and the manifest only allowlists some of them; typos or name drift between the code's package string and the manifest entry; new optional dependency added without a capability entry.
Related errors
- capability for process:exec {desired_command} {desired_args:
- capability for download_file {desired_url} is not granted by
- capability for process:exec {desired_command} {desired_args:
- mismatched versions: ({}) != ({})
- grammar name '{grammar_name}' must be written in snake_case:
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/1bbf033d814ba933.
Report an issue: GitHub.