{"record":{"id":"005b32f1eb3727d4","repo":"denoland/deno","slug":"not-a-directory","errorCode":null,"errorMessage":"Not a directory","messagePattern":"Not a directory","errorType":"exception","errorClass":"FsError","httpStatus":null,"severity":"error","filePath":"cli/rt/file_system.rs","lineNumber":157,"sourceCode":"    RealFs.cwd()\n  }\n\n  fn tmp_dir(&self) -> FsResult<PathBuf> {\n    RealFs.tmp_dir()\n  }\n\n  fn chdir(&self, path: &CheckedPath) -> FsResult<()> {\n    if self.is_vfs_path(path) {\n      // The process working directory can't actually be changed to a path\n      // inside the embedded virtual file system, but applications (e.g.\n      // Next.js standalone builds) commonly chdir into their own directory.\n      // Verify the target exists and is a directory in the VFS and treat the\n      // change as a no-op rather than failing with NotSupported. Note that\n      // Deno.cwd() still reports the previous (real) working directory.\n      if self.vfs.stat(path)?.as_fs_stat().is_directory {\n        Ok(())\n      } else {\n        Err(FsError::Io(std::io::Error::new(\n          ErrorKind::NotADirectory,\n          \"Not a directory\",\n        )))\n      }\n    } else {\n      RealFs.chdir(path)\n    }\n  }\n\n  fn umask(&self, mask: Option<u32>) -> FsResult<u32> {\n    RealFs.umask(mask)\n  }\n\n  fn open_sync(\n    &self,\n    path: &CheckedPath,\n    options: OpenOptions,\n  ) -> FsResult<Rc<dyn DenoFile>> {","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/rt/file_system.rs#L139-L175","documentation":"In a compiled (deno compile) binary, paths inside the embedded VFS cannot become the real process working directory, so chdir is emulated: if the VFS target exists and is a directory, the call succeeds as a no-op (Deno.cwd() keeps reporting the old real directory); if the target exists but is not a directory, you get io::ErrorKind::NotADirectory 'Not a directory'.","triggerScenarios":"A compiled app calling Deno.chdir (or process.chdir in Node-compat code, or a dependency like Next.js standalone doing chdir(__dirname)) where the VFS path resolves to a file or symlink-to-file rather than a directory; e.g. chdir('/deno-dir/src/mod.ts') or a __dirname computed to point at a file.","commonSituations":"Ported Node scripts that chdir into paths derived from import.meta/require paths and landing on files; case-sensitivity or symlink differences making a path that is a dir on the host a file in the VFS; hardcoded absolute paths from the build machine baked into the compiled app.","solutions":["Point chdir at an actual directory (e.g. the directory of the entry module: new URL('.', import.meta.url))","Guard with Deno.statSync first and check .isDirectory before chdir","Remember that in compiled binaries chdir into the VFS is a no-op for the OS — code relying on the CWD actually changing (relative file writes) must instead resolve paths explicitly against the VFS root"],"exampleFix":"// before (compiled binary; mod.ts is a file)\nDeno.chdir(new URL('.', import.meta.url).pathname + 'mod.ts');\n\n// after\nconst dir = new URL('.', import.meta.url).pathname;\nif (Deno.statSync(dir).isDirectory) Deno.chdir(dir);","handlingStrategy":"validation","validationCode":"// Safe chdir that tolerates the compiled-VFS no-op semantics\nimport { isDir } from \"./util.ts\";\nexport function chdirSafe(p: string) {\n  const st = Deno.statSync(p); // follows symlinks\n  if (!st.isDirectory) throw new Error(`chdir target is not a directory: ${p}`);\n  Deno.chdir(p);\n}","typeGuard":"function isDirectorySync(p: string): boolean {\n  try { return Deno.statSync(p).isDirectory; } catch { return false; }\n}","tryCatchPattern":"try {\n  process.chdir(dir); // or Deno.chdir(dir)\n} catch (e) {\n  if (e instanceof Error && /Not a directory/i.test(e.message)) {\n    // derive the real directory of the current module instead\n    Deno.chdir(new URL(\".\", import.meta.url).pathname);\n  } else throw e;\n}","preventionTips":["Derive directories from module URLs (new URL('.', import.meta.url)), never from file paths","stat-check isDirectory before every chdir in code that runs compiled","Remember compiled VFS chdir is a no-op: never rely on relative writes after it"],"tags":["compile","vfs","chdir","working-directory","filesystem"],"backgroundTag":"not-a-directory","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}