oven-sh/bun · error · bun_install::Error

NotDir

Error message

NotDir

What it means

A path component that should be a directory is actually a file. Fires during filesystem operations in the installer when a non-directory (ENOENT/EISDIR-style mismatch) is encountered where package directories are expected.

Solutions

  1. Remove the conflicting file that occupies the expected directory path
  2. Clear node_modules and cache, then reinstall
  3. Check for filesystem corruption or conflicting project files at the install path

Example fix

# before
node_modules/@scope   # a stray file
bun install           # -> NotDir

# after
rm node_modules/@scope
bun install
Defensive patterns

Strategy: validation

Validate before calling

import { statSync } from "node:fs";

for (const p of ["node_modules/@types", "node_modules/@my-scope"]) {
  try {
    if (!statSync(p).isDirectory()) {
      console.error(p, "is a file; remove it before install");
      process.exit(1);
    }
  } catch {
    // absent is fine
  }
}

Prevention

When it happens

Trigger: node_modules/@scope exists as a file instead of a directory; a file sits where the installer wants to mkdir (cache layout, bin dir); a lockfile path embeds a file where a folder is expected.

Common situations: Stray file created inside node_modules by a script or editor; partially cleaned node_modules; flat-file tools writing placeholder files with directory-shaped names; case-collision leftovers on case-insensitive filesystems.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/d4aa1962d7c21c4c. Report an issue: GitHub.

Appendix: source

Thrown at src/install/error.rs:7

#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum Error {
    #[error("FileNotFound")]
    FileNotFound,
    #[error("AccessDenied")]
    AccessDenied,
    #[error("NotDir")]
    NotDir,
    #[error("NameTooLong")]
    NameTooLong,
    #[error("SymLinkLoop")]
    SymLinkLoop,
    #[error("SystemFdQuotaExceeded")]
    SystemFdQuotaExceeded,
    #[error("SystemResources")]
    SystemResources,
    #[error("DeviceBusy")]
    DeviceBusy,
    #[error("TarballHTTP400")]
    TarballHTTP400,
    #[error("TarballHTTP401")]
    TarballHTTP401,
    #[error("TarballHTTP402")]
    TarballHTTP402,
    #[error("TarballHTTP403")]

View on GitHub (pinned to 8c5296ac45)