affaan-m/ECC · error · Error

Failed to create directory

Error message

Failed to create directory '${dirPath}': ${err.message}

What it means

ensureDir creates a directory (and parents) if it does not exist, wrapping fs.mkdirSync failures. EEXIST is tolerated as a benign race with another process; any other mkdir error (permissions, invalid path, ENOTDIR, EROFS) is rethrown with the path and the underlying OS message.

Solutions

  1. Read the wrapped OS error (e.g. EACCES, ENOTDIR, EROFS) in the message to identify the cause.
  2. If EACCES: fix permissions on the parent directory (chown/chmod) or run with appropriate rights.
  3. If ENOTDIR: remove or rename the file that occupies a path segment where a directory is required.
  4. If EROFS: write to a writable location instead of a read-only mount.

Example fix

// before: a regular file blocks the path
ls -la ~/.claude/state   # it's a file
// after
rm ~/.claude/state && mkdir -p ~/.claude/state
Defensive patterns

Strategy: try-catch

Validate before calling

function canCreateDir(dirPath) {
  const parent = path.dirname(dirPath);
  if (!fs.existsSync(parent)) return canCreateDir(parent);
  const st = fs.statSync(parent);
  if (!st.isDirectory()) return false;      // ENOTDIR
  try { fs.accessSync(parent, fs.constants.W_OK); return true; }
  catch { return false; }                    // EACCES/EROFS
}

Type guard

const isDir = (p) => { try { return fs.statSync(p).isDirectory(); } catch { return false; } };

Try / catch

try {
  ensureDir(dirPath);
} catch (err) {
  if (err.message.includes('EACCES')) console.error(`No write permission for ${dirPath} — chown/chmod or pick another location`);
  else if (err.message.includes('ENOTDIR')) console.error(`A file is blocking ${dirPath} — remove/rename it`);
  else throw err;
}

Prevention

When it happens

Trigger: Calling ensureDir (directly or via callers like writeSessionLease, saveAliases, appendRunRecord) when the path's parent is a file (ENOTDIR), the process lacks write permission on the parent (EACCES), the path segment is malformed, or the filesystem is read-only.

Common situations: A file exists where a directory component of dirPath is expected; running the script as a user without write access to ~/.claude or the project dir; pointing the CLI at a read-only mounted volume or a path with stray characters/quotes.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/417e227976a731ad. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/utils.js:102

function getTempDir() {
  return os.tmpdir();
}

/**
 * Ensure a directory exists (create if not)
 * @param {string} dirPath - Directory path to create
 * @returns {string} The directory path
 * @throws {Error} If directory cannot be created (e.g., permission denied)
 */
function ensureDir(dirPath) {
  try {
    if (!fs.existsSync(dirPath)) {
      fs.mkdirSync(dirPath, { recursive: true });
    }
  } catch (err) {
    // EEXIST is fine (race condition with another process creating it)
    if (err.code !== 'EEXIST') {
      throw new Error(`Failed to create directory '${dirPath}': ${err.message}`);
    }
  }
  return dirPath;
}

/**
 * Get current date in YYYY-MM-DD format
 */
function getDateString() {
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0');
  const day = String(now.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}

/**
 * Get current time in HH:MM format

View on GitHub (pinned to 8321021c54)