{"record":{"id":"b5588c7d99dc9b84","repo":"zed-industries/zed","slug":"capability-for-download-file-desired-url-is-not","errorCode":null,"errorMessage":"capability for download_file {desired_url} is not granted by the extension host","messagePattern":"capability for download_file (.+?) is not granted by the extension host","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/extension_host/src/capability_granter.rs","lineNumber":59,"sourceCode":"            bail!(\n                \"capability for process:exec {desired_command} {desired_args:?} is not granted by the extension host\",\n            );\n        }\n\n        Ok(())\n    }\n\n    pub fn grant_download_file(&self, desired_url: &Url) -> Result<()> {\n        let is_allowed = self\n            .granted_capabilities\n            .iter()\n            .any(|capability| match capability {\n                ExtensionCapability::DownloadFile(capability) => capability.allows(desired_url),\n                _ => false,\n            });\n\n        if !is_allowed {\n            bail!(\n                \"capability for download_file {desired_url} is not granted by the extension host\",\n            );\n        }\n\n        Ok(())\n    }\n\n    pub fn grant_npm_install_package(&self, package_name: &str) -> Result<()> {\n        let is_allowed = self\n            .granted_capabilities\n            .iter()\n            .any(|capability| match capability {\n                ExtensionCapability::NpmInstallPackage(capability) => {\n                    capability.allows(package_name)\n                }\n                _ => false,\n            });\n","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/extension_host/src/capability_granter.rs#L41-L77","documentation":"Before a WASM extension may download a file, the host calls CapabilityGranter::grant_download_file, which requires a `download_file` capability in the manifest whose host and path patterns match the URL (host must match exactly or be `*`; path segments match exactly, `*` for one segment, `**` for everything from that point on, and the pattern must cover the whole path). If no granted capability matches, it bails with the denied URL.","triggerScenarios":"Extension downloads from a URL whose host or path is not covered by any [[capabilities]] kind = \"download_file\" entry — e.g. the manifest allowlists github.com but code fetches from raw.githubusercontent.com, or the path pattern is shorter than the actual URL path.","commonSituations":"Adding a second download source (CDN, releases CDN, different subdomain) without extending the allowlist; path patterns like [\"specific-owner\", \"*\"] failing on deeper URLs because every segment must be covered; copy-pasted capability entries that don't match the actual fetch URL.","solutions":["Compare the URL in the error with the manifest entry; mismatched host is the most common cause (subdomains must be listed separately).","Broaden the path pattern using \"**\" or add the exact host, e.g. [[capabilities]] kind = \"download_file\" host = \"objects.githubusercontent.com\" path = [\"**\"].","Rebuild/reinstall the extension so the updated manifest takes effect."],"exampleFix":"# before\n[[capabilities]]\nkind = \"download_file\"\nhost = \"github.com\"\npath = [\"**\"]\n\n# after: also cover GitHub's release-asset CDN\n[[capabilities]]\nkind = \"download_file\"\nhost = \"github.com\"\npath = [\"**\"]\n\n[[capabilities]]\nkind = \"download_file\"\nhost = \"objects.githubusercontent.com\"\npath = [\"**\"]","handlingStrategy":"validation","validationCode":"fn download_allowed(manifest: &ExtensionManifest, url: &url::Url) -> bool {\n    manifest.capabilities.iter().any(|capability| match capability {\n        ExtensionCapability::DownloadFile(capability) => capability.allows(url),\n        _ => false,\n    })\n}\n\n// before fetching in extension code\nlet url: url::Url = \"https://objects.githubusercontent.com/...\".parse()?;\nassert!(download_allowed(&manifest, &url), \"url host/path not covered by a download_file capability\");","typeGuard":"fn is_download_capable(capability: &ExtensionCapability) -> bool {\n    matches!(capability, ExtensionCapability::DownloadFile(_))\n}","tryCatchPattern":null,"preventionTips":["List every host the code downloads from — subdomains are separate hosts.","Remember the path pattern must cover the entire URL path; end with \"**\" for deep paths.","Centralize URL construction in one function so allowlist review is single-place."],"tags":["security","capability","extension","download","manifest"],"backgroundTag":"permission-denied-capability","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}