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
- Read the wrapped OS error (e.g. EACCES, ENOTDIR, EROFS) in the message to identify the cause.
- If EACCES: fix permissions on the parent directory (chown/chmod) or run with appropriate rights.
- If ENOTDIR: remove or rename the file that occupies a path segment where a directory is required.
- 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
- Never place a regular file at a path segment the tool uses as a directory
- Run the tool as a user with write access to the project/home config directories
- Avoid read-only mounts as output roots
- Quote paths in shell invocations to avoid stray characters in dirPath
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
- Cannot read local asset
- ECC_MEMORY_INCOMPLETE
- destination is not writable by the current user: . Fix the…
- missing output directory
- output parent directory must already exist
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 formatView on GitHub (pinned to 8321021c54)