{"record":{"id":"d69bc7af3e3765a8","repo":"tauri-apps/tauri","slug":"asset-protocol-not-configured-to-allow-the-path","errorCode":null,"errorMessage":"asset protocol not configured to allow the path: {path}","messagePattern":"asset protocol not configured to allow the path: (.+?)","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"crates/tauri/src/protocol/asset.rs","lineNumber":48,"sourceCode":"  request: Request<Vec<u8>>,\n  scope: &scope::fs::Scope,\n  window_origin: &str,\n) -> Result<Response<Cow<'static, [u8]>>, Box<dyn std::error::Error>> {\n  // skip leading `/`\n  let path = percent_encoding::percent_decode(&request.uri().path().as_bytes()[1..])\n    .decode_utf8_lossy()\n    .to_string();\n\n  let mut resp = Response::builder().header(\"Access-Control-Allow-Origin\", window_origin);\n\n  if let Err(e) = SafePathBuf::new(path.clone().into()) {\n    log::error!(\"asset protocol path \\\"{path}\\\" is not valid: {e}\");\n    return resp.status(403).body(Vec::new().into()).map_err(Into::into);\n  }\n\n  if !scope.is_allowed(&path) {\n    log::error!(\"asset protocol not configured to allow the path: {path}\");\n    return resp.status(403).body(Vec::new().into()).map_err(Into::into);\n  }\n\n  // Separate block for easier error handling\n  let mut file = match File::open(path.clone()) {\n    Ok(file) => file,\n    Err(e) => {\n      #[cfg(target_os = \"android\")]\n      {\n        if path.starts_with(\"/storage/emulated/0/Android/data/\") {\n          log::error!(\n            \"Failed to open Android external storage file '{path}': {e}. This may be due to missing storage permissions.\"\n          );\n        }\n      }\n      return if e.kind() == std::io::ErrorKind::NotFound {\n        log::error!(\"File does not exist at path: {path}\");\n        return resp.status(404).body(Vec::new().into()).map_err(Into::into);\n      } else if e.kind() == std::io::ErrorKind::PermissionDenied {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/tauri-apps/tauri/blob/460ec35447493200d64290dd7f015d5a91d0fd58/crates/tauri/src/protocol/asset.rs#L30-L66","documentation":"The asset protocol enforces the configured asset scope: only paths matching the app's assetProtocol scope (allowlist) in tauri.conf.json are served. When the requested path is a valid path but not allowed by the scope, the handler logs this error and returns 403.","triggerScenarios":"A webview request to asset:// for a filesystem path that is not covered by app.security.assetProtocol.scope (with the builtin asset protocol enabled), evaluated in get_response via scope.is_allowed().","commonSituations":"Developer enables the asset protocol but forgets to add the directory to scope; user picks a file outside the configured scope glob via a file dialog; scope patterns too narrow ($HOME/** missing, wrong glob syntax).","solutions":["Add the needed directories/patterns to app.security.assetProtocol.scope in tauri.conf.json (e.g. \"$HOME/**\", \"/mnt/**\")","Set assetProtocol.enable to true and restart/rebuild the app after config changes","Have the app copy or stream files outside the scope via a custom Tauri command instead of the asset protocol"],"exampleFix":"// before (tauri.conf.json)\n\"assetProtocol\": { \"enable\": true, \"scope\": [] }\n// after\n\"assetProtocol\": { \"enable\": true, \"scope\": [\"$HOME/**\", \"$DESKTOP/**\"] }","handlingStrategy":"validation","validationCode":"// tauri.conf.json check before shipping\n\"app\": { \"security\": { \"assetProtocol\": { \"enable\": true, \"scope\": [\"$HOME/**\", \"$DESKTOP/**\"] } } }","typeGuard":"function isWithinScope(path: string, scopePrefixes: string[]): boolean {\n  return scopePrefixes.some(pfx => path.startsWith(pfx.replace('$HOME', homeDir)));\n}","tryCatchPattern":"const resp = await fetch(assetUrl);\nif (resp.status === 403) {\n  // likely scope denial; fall back to a custom command that reads the file\n  const data = await invoke('read_external_file', { path });\n}","preventionTips":["Keep the assetProtocol scope in sync with every directory your app reads","Test file-dialog-picked paths against the scope during development","Prefer copying files into the app data dir instead of serving them from arbitrary locations"],"tags":["tauri","security","scope","http-403","configuration"],"backgroundTag":"permission-denied","analyzedSha":"460ec35447493200d64290dd7f015d5a91d0fd58","analyzedAt":"2026-09-18T23:55:51.277Z","contentChangedAt":"2026-09-18T23:55:51.277Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}