zed-industries/zed · error · anyhow::Error

capability for process:exec {desired_command} {desired_args:

Error message

capability for process:exec {desired_command} {desired_args:?} is not granted by the extension host

What it means

The extension host mediates every process a WASM extension wants to spawn through CapabilityGranter::grant_process_exec. It only allows the call if some `process:exec` capability declared in the extension manifest matches the exact desired command and arguments (per ProcessExecCapability::allows: command must match exactly or be `*`; args must match element-wise, where `*` is a single-arg wildcard and a trailing `**` permits any remaining args). Otherwise it bails with the requested command and args.

Source

Thrown at crates/extension_host/src/capability_granter.rs:41

    pub fn grant_exec(
        &self,
        desired_command: &str,
        desired_args: &[impl AsRef<str> + std::fmt::Debug],
    ) -> Result<()> {
        self.manifest.allow_exec(desired_command, desired_args)?;

        let is_allowed = self
            .granted_capabilities
            .iter()
            .any(|capability| match capability {
                ExtensionCapability::ProcessExec(capability) => {
                    capability.allows(desired_command, desired_args)
                }
                _ => false,
            });

        if !is_allowed {
            bail!(
                "capability for process:exec {desired_command} {desired_args:?} is not granted by the extension host",
            );
        }

        Ok(())
    }

    pub fn grant_download_file(&self, desired_url: &Url) -> Result<()> {
        let is_allowed = self
            .granted_capabilities
            .iter()
            .any(|capability| match capability {
                ExtensionCapability::DownloadFile(capability) => capability.allows(desired_url),
                _ => false,
            });

        if !is_allowed {
            bail!(

View on GitHub (pinned to f4178619ac)

Solutions

  1. Add a matching entry to extension.toml: [[capabilities]] kind = "process:exec" with the exact command and args shown in the error message.
  2. Use "*" for one wildcard argument and a trailing "**" only when the command legitimately takes arbitrary trailing arguments.
  3. Rebuild and reinstall/re-test the extension (`zed extension test`) so the updated manifest is loaded.

Example fix

# before: extension.toml has no capabilities section

# after
[[capabilities]]
kind = "process:exec"
command = "git"
args = ["status", "**"]
Defensive patterns

Strategy: validation

Validate before calling

fn process_exec_allowed(
    manifest: &ExtensionManifest,
    desired_command: &str,
    desired_args: &[&str],
) -> bool {
    manifest.capabilities.iter().any(|capability| match capability {
        ExtensionCapability::ProcessExec(capability) => {
            capability.allows(desired_command, desired_args)
        }
        _ => false,
    })
}

// before spawning from extension code
assert!(process_exec_allowed(&manifest, "git", &["status", "-s"]),
    "add a process:exec capability to extension.toml first");

Type guard

fn is_process_exec_capable(capability: &ExtensionCapability) -> bool {
    matches!(capability, ExtensionCapability::ProcessExec(_))
}

Prevention

When it happens

Trigger: Extension code invokes a subprocess (e.g. exec of `git status`) while extension.toml has no [[capabilities]] entry with kind = "process:exec", or the declared args no longer match because the code now passes different flags or more arguments than the manifest allows.

Common situations: Adding a new subprocess call or an extra flag to an existing one without updating the manifest allowlist; switching from exact args to variadic args without a trailing "**"; re-publishing an old extension against a host that started enforcing capabilities.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/b16e5b66fac3c333. Report an issue: GitHub.