affaan-m/ECC · error
Failed to create directory '${dirPath}': ${err.message}
Error message
Failed to create directory '${dirPath}': ${err.message} What it means
ensureDir wraps fs.mkdirSync({recursive:true}) and re-throws any error whose code is not EEXIST (EEXIST is tolerated as a benign race). It fires for permission, disk-space, read-only-filesystem, path-too-long, and quota errors coming from the OS. The thrown message interpolates dirPath and the underlying err.message so the caller can see both the target and the OS reason.
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 formatView on GitHub (pinned to 01e15490f0)
Solutions
- Check write permission on the parent: `ls -ld <parent>` and `test -w <parent>`; chmod/chown or rerun as the owner.
- Free disk/inodes: `df -h <dirPath>` and `df -i <dirPath>`; clear space if full.
- Confirm the path is on a writable filesystem (not a read-only mount) and that no regular file occupies dirPath.
- Shorten or sanitize dirPath if it is abnormally long, or move the workspace under a shallower root.
Example fix
// before
ensureDir('/opt/ecc/state'); // EACCES if /opt is root-owned
// after — write under a user-owned path and surface mkdir errors with their code
function ensureDirSafe(dirPath) {
try {
fs.mkdirSync(dirPath, { recursive: true });
} catch (err) {
if (err.code !== 'EEXIST') {
throw new Error(`Failed to create directory '${dirPath}' (${err.code}): ${err.message}`);
}
}
return dirPath;
}
ensureDirSafe(path.join(os.homedir(), '.local', 'ecc', 'state')); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: parent must exist and be writable; path must not be a regular file.
const fs = require('fs');
const path = require('path');
function canCreateDir(dirPath) {
const parent = path.dirname(path.resolve(dirPath));
try {
fs.accessSync(parent, fs.constants.W_OK);
} catch {
return false;
}
try {
const st = fs.statSync(dirPath);
return st.isDirectory(); // exists as dir is fine; exists as file is not
} catch { return true; } // nothing there yet
}
if (!canCreateDir(target)) throw new Error(`Cannot create ${target}: parent not writable or target is a file.`); Try / catch
try {
ensureDir(target);
} catch (err) {
if (/Failed to create directory/.test(err.message)) {
// Retry once on a user-owned fallback, or surface a friendlier message.
const fallback = path.join(os.homedir(), '.cache', 'ecc');
if (fallback !== target) { ensureDir(fallback); return fallback; }
}
throw err;
} Prevention
- Run the CLI as the user that owns the target directory.
- Avoid read-only mounts for writable state; verify with `mount | grep <path>`.
- Monitor disk/inode usage in CI before writing.
- Sanitize/normalize long paths before ensureDir to avoid ENAMETOOLONG.
When it happens
Trigger: Calling ensureDir on a path under a directory the process has no write permission to (EACCES). Target on a read-only mount (EROFS). Disk full or inode quota exhausted (ENOSPC). Path longer than PATH_MAX (ENAMETOOLONG). A file (not directory) already exists at dirPath (ENOTDIR/EEXIST-on-file — though EEXIST is swallowed, ENOTDIR on a parent is not).
Common situations: Running the CLI as a different user than owns the project dir. Docker/container with a read-only volume mount. CI runner out of disk. Symlink loop in the target path. NFS/Homebrew prefixes with restricted permissions on macOS.
Related errors
- Failed to read ${label}: ${error.message}
- ${label} destination is not writable by the current user: ${
- Failed to save package manager preference: ${err.message}
- Failed to save package manager config to ${configPath}: ${er
- Standard input remained unavailable after ${maxRetryWaitMs}m
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/417e227976a731ad.
Report an issue: GitHub.