{"record":{"id":"5fba48b714c29d05","repo":"tauri-apps/tauri","slug":"path-is-not-a-directory","errorCode":null,"errorMessage":"'${path}' is not a directory.","messagePattern":"'(.+?)' is not a directory\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/api/rollup.config.ts","lineNumber":104,"sourceCode":"    writeBundle() {\n      // copy necessary files like `CHANGELOG.md` , `README.md` and Licenses to `./dist`\n      fg.sync('(LICENSE*|*.md|package.json)').forEach((f) =>\n        copyFileSync(f, `dist/${f}`)\n      )\n    }\n  }\n}\n\nfunction cleanDir(path: string) {\n  let dir: Dir\n  try {\n    dir = opendirSync(path)\n  } catch (err: any) {\n    switch (err.code) {\n      case 'ENOENT':\n        return // Noop when directory don't exists.\n      case 'ENOTDIR':\n        throw new Error(`'${path}' is not a directory.`)\n      default:\n        throw err\n    }\n  }\n\n  let file = dir.readSync()\n  while (file) {\n    const filePath = join(path, file.name)\n    rmSync(filePath, { recursive: true })\n    file = dir.readSync()\n  }\n  dir.closeSync()\n}\n","sourceCodeStart":86,"sourceCodeEnd":118,"githubUrl":"https://github.com/tauri-apps/tauri/blob/2f1cd75b0f3fb72e6870d719bbfeadedcf8ca884/packages/api/rollup.config.ts#L86-L118","documentation":"The @tauri-apps/api build script (packages/api/rollup.config.ts) calls cleanDir() on packages/api/dist before rollup starts. cleanDir() opens the path with fs.opendirSync(). If the operating system returns ENOTDIR, the path exists but is not a directory (usually a regular file named dist). The script then throws this error. A missing directory (ENOENT) is ignored, so the error proves that something occupies the dist path as a non-directory.","triggerScenarios":"Run the packages/api build (rollup -c / yarn build) while packages/api/dist exists as a regular file or as a symlink to a file. opendirSync(dist) fails with ENOTDIR and cleanDir throws at rollup.config.ts:104. Permission errors (EACCES, EPERM) take the default branch and rethrow the raw fs error instead.","commonSituations":"A CI step or shell redirect created a file named dist (for example 'curl -o dist ...' or '> dist'). A symlink points dist to a file. A previous artifact copy replaced the directory. The build runs in a dirty working tree after such an operation.","solutions":["Remove the offending path: rm -f packages/api/dist (or delete the symlink), then rerun the build.","Inspect what dist is: ls -l packages/api/dist. If it is a symlink to a file, delete it or point it to a directory.","Find the writer: search CI steps and npm scripts for commands that write to ./dist as a file, and fix them.","For CI, run the build from a clean checkout (git clean -fdx) so stale paths cannot survive."],"exampleFix":"// before: packages/api/dist is a regular file\n$ ls -l packages/api/dist\n-rw-r--r-- 1 user 0 dist\n$ rollup -c\n// Error: '/repo/packages/api/dist' is not a directory.\n\n// after\n$ rm -f packages/api/dist\n$ rollup -c   // cleanDir no-ops on ENOENT, then builds fresh","handlingStrategy":"validation","validationCode":"import { statSync, rmSync } from 'fs'\nimport { join } from 'path'\n\n// run before cleanDir(join(__dirname, './dist'))\nfunction ensureCleanableDir(path: string) {\n  let st\n  try {\n    st = statSync(path) // follows symlinks\n  } catch {\n    return // path absent: cleanDir no-ops on ENOENT\n  }\n  if (!st.isDirectory()) {\n    rmSync(path, { force: true }) // remove the offending file/symlink\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  cleanDir(dist)\n} catch (err) {\n  if (/is not a directory\\./.test(err.message)) {\n    rmSync(dist, { force: true }) // drop the non-directory\n    cleanDir(dist)                // retry once\n  } else {\n    throw err // EACCES and other fs errors: surface as-is\n  }\n}","preventionTips":["Treat packages/api/dist as build output only; never redirect a file to that path in scripts or CI.","Run builds from a clean checkout (git clean -fdx) in CI so stale paths cannot survive.","If dist must be a symlink, point it to a directory, never to a file.","Audit npm scripts for commands that write to ./dist with a shell redirect."],"tags":["rollup","filesystem","build-config","tauri-api","cleanup"],"backgroundTag":null,"analyzedSha":"2f1cd75b0f3fb72e6870d719bbfeadedcf8ca884","analyzedAt":"2026-08-16T04:18:42.486Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}