{"record":{"id":"f6e037c8d5fb6a90","repo":"tauri-apps/tauri","slug":"is-not-a-file","errorCode":null,"errorMessage":"{:?} is not a file","messagePattern":"(.+?) is not a file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri-build/src/lib.rs","lineNumber":50,"sourceCode":"mod codegen;\nmod manifest;\nmod mobile;\nmod static_vcruntime;\n\n#[cfg(feature = \"codegen\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"codegen\")))]\npub use codegen::context::CodegenContext;\n\npub use acl::{AppManifest, DefaultPermissionRule, InlinedPlugin};\n\nfn copy_file(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<()> {\n  let from = from.as_ref();\n  let to = to.as_ref();\n  if !from.exists() {\n    return Err(anyhow::anyhow!(\"{:?} does not exist\", from));\n  }\n  if !from.is_file() {\n    return Err(anyhow::anyhow!(\"{:?} is not a file\", from));\n  }\n  let dest_dir = to.parent().expect(\"No data in parent\");\n  fs::create_dir_all(dest_dir)?;\n  fs::copy(from, to)?;\n  Ok(())\n}\n\nfn copy_binaries(\n  binaries: ResourcePaths,\n  target_triple: &str,\n  path: &Path,\n  package_name: Option<&str>,\n) -> Result<()> {\n  for src in binaries {\n    let src = src?;\n    println!(\"cargo:rerun-if-changed={}\", src.display());\n    let file_name = src\n      .file_name()","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/tauri-apps/tauri/blob/460ec35447493200d64290dd7f015d5a91d0fd58/crates/tauri-build/src/lib.rs#L32-L68","documentation":"copy_file in tauri-build rejects sources that exist but are not regular files (e.g. directories, symlinks to dirs, or special files), because fs::copy only works on files. The offending path is embedded in the message.","triggerScenarios":"A `bundle.resources` or frameworks entry in tauri.conf.json resolves to a directory or non-regular file when copy_file is called from copy_binaries/copy_resources/copy_frameworks.","commonSituations":"Pointing `resources` directly at a directory instead of using a glob or directory-copy semantics, a symlink to a directory, or a config path that accidentally matches a folder.","solutions":["Change the config entry to point to a concrete file, or use a glob pattern (e.g. `dir/**`) to include directory contents","Replace symlink-to-directory sources with the real file path or copy semantics","Verify with `ls -la` / `Get-Item` that the path is a regular file"],"exampleFix":"// before (tauri.conf.json)\n\"resources\": [\"assets/configs\"]  // is a directory\n// after\n\"resources\": [\"assets/configs/**\"]","handlingStrategy":"validation","validationCode":"const isRegularFile = (p: string) => { try { return fs.statSync(p).isFile(); } catch { return false; } };\nfor (const r of cfg.bundle?.resources ?? []) {\n  const p = resolve('src-tauri', r.replace(/[*].*$/, ''));\n  if (fs.existsSync(p) && !isRegularFile(p) && !r.includes('*')) throw new Error(`Use a glob for directories: ${r}`);\n}","typeGuard":"const isFile = (p: string): p is string => fs.statSync(p, { throwIfNoEntry: false })?.isFile() === true;","tryCatchPattern":"try {\n  await copy(from, to);\n} catch (e) {\n  if (String(e).includes('is not a file')) throw new Error(`Point resources at files or use ** globs: ${e.message}`);\n  throw e;\n}","preventionTips":["Never point `resources` directly at a directory entry; use `dir/**`","Check symlinks resolve to regular files on the build machine","Lint tauri.conf.json paths in CI before building"],"tags":["build","filesystem","tauri-build","path-type"],"backgroundTag":"incompatible-source-type","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"}