{"record":{"id":"cd80c6f832e85c40","repo":"tauri-apps/tauri","slug":"can-t-read-source-directory","errorCode":null,"errorMessage":"Can't read source directory","messagePattern":"Can't read source directory","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri-bundler/src/bundle/updater_bundle.rs","lineNumber":259,"sourceCode":"  Ok(dest_path.to_owned())\n}\n\n#[cfg(target_os = \"macos\")]\nfn create_tar_from_src<P: AsRef<Path>, W: Write>(src_dir: P, dest_file: W) -> crate::Result<W> {\n  let src_dir = src_dir.as_ref();\n  let mut builder = tar::Builder::new(dest_file);\n  builder.follow_symlinks(false);\n  builder.append_dir_all(src_dir.file_name().expect(\"Path has no file_name\"), src_dir)?;\n  builder.into_inner().map_err(Into::into)\n}\n\n#[cfg(target_os = \"linux\")]\nfn create_tar_from_src<P: AsRef<Path>, W: Write>(src_dir: P, dest_file: W) -> crate::Result<W> {\n  let src_dir = src_dir.as_ref();\n  let mut tar_builder = tar::Builder::new(dest_file);\n\n  // validate source type\n  let file_type = fs::metadata(src_dir).expect(\"Can't read source directory\");\n  // if it's a file don't need to walkdir\n  if file_type.is_file() {\n    let mut src_file = fs::File::open(src_dir)?;\n    let file_name = src_dir\n      .file_name()\n      .expect(\"Can't extract file name from path\");\n\n    tar_builder.append_file(file_name, &mut src_file)?;\n  } else {\n    for entry in walkdir::WalkDir::new(src_dir) {\n      let entry = entry?;\n      let src_path = entry.path();\n      if src_path == src_dir {\n        continue;\n      }\n\n      // We add the .parent() because example if we send a path\n      // /dev/src-tauri/target/debug/bundle/osx/app.app","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/tauri-apps/tauri/blob/460ec35447493200d64290dd7f015d5a91d0fd58/crates/tauri-bundler/src/bundle/updater_bundle.rs#L241-L277","documentation":"Panic from `.expect(\"Can't read source directory\")` on `fs::metadata(src_dir)` in the Linux `create_tar_from_src`. `fs::metadata` returns `Err` (and the expect panics) when the source path does not exist, permission is denied on a parent directory, or the path is invalid. The bundler needs the file type to decide between single-file and directory tar packaging, so it treats a failed stat as fatal.","triggerScenarios":"Calling `create_tar`/`create_tar_from_src` on Linux when `src_dir` does not exist on disk, is unreadable due to filesystem permissions, is a broken symlink resolved before stat, or the process lacks search permission on a path component.","commonSituations":"The updater artifact was deleted or moved between build steps, a CI cache miss left the bundle directory absent, AppImage/deb output path misconfigured in tauri.conf.json, or running the bundler in a container with restricted volume permissions.","solutions":["Verify `src_dir` exists before bundling: run `std::fs::metadata(src_dir)` yourself and report a clear error","Check the configured bundle output path in tauri.conf.json / CLI flags points at the produced artifact","Fix filesystem permissions on the path and its parents (read + execute bits) for the user running the bundler","If the path is produced by a previous build step, ensure that step succeeded and completed before invoking the bundler"],"exampleFix":"// before\ncreate_tar(\"target/release/bundle/app\", dest)?; // panics if missing\n// after\nlet src = Path::new(\"target/release/bundle/app\");\nlet meta = std::fs::metadata(src)\n    .map_err(|e| anyhow!(\"updater source missing: {e}\"))?;\ncreate_tar(src, dest)?;","handlingStrategy":"validation","validationCode":"fn ensure_readable_dir(p: &std::path::Path) -> Result<(), String> {\n    match std::fs::metadata(p) {\n        Ok(m) if m.is_dir() => Ok(()),\n        Ok(_) => Err(format!(\"not a directory: {}\", p.display())),\n        Err(e) => Err(format!(\"cannot stat {}: {}\", p.display(), e)),\n    }\n}\n// call before create_tar on Linux","typeGuard":"fn is_readable_dir(p: &std::path::Path) -> bool {\n    std::fs::metadata(p).map(|m| m.is_dir()).unwrap_or(false)\n}","tryCatchPattern":"match std::fs::metadata(src_dir) {\n    Ok(meta) if meta.is_dir() => create_tar(src_dir, dest)?,\n    Ok(_) => return Err(anyhow!(\"updater source is not a directory\")),\n    Err(e) => return Err(anyhow!(\"updater source missing/unreadable: {e}\")),\n}","preventionTips":["Check the source exists with fs::metadata before bundling","Ensure previous build steps completed and produced the artifact","Fix permissions (r+x on directories) for the user running the bundler","Verify bundle output paths in tauri.conf.json match where artifacts are actually written"],"tags":["filesystem","panic","updater","linux","io"],"backgroundTag":"file-read-failed","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"}