Node.js中async mkdir报EEXIST错误但目录实际不存在
首先,咱们来拆解你遇到的这个诡异问题——明明目标目录不存在,却收到EEXIST错误,在Linux系统下通常有几个核心原因,以及对应的解决办法:
可能的触发原因
1. 路径中存在同名文件(而非目录)
这是最常见的情况:你要创建的路径里,某个节点不是目录,而是一个普通文件。比如/home/msh/Documents/arraba-api/app/build/plugin/images/images/5/profile可能已经是一个文件,而非空目录,这时候mkdir就会抛出EEXIST错误,因为它无法在已有文件的位置创建同名目录。
你可以在终端用以下命令验证:
ls -l /home/msh/Documents/arraba-api/app/build/plugin/images/images/5/
如果输出里profile或cars的前缀是-(表示普通文件)而非d(表示目录),那就是这个问题。
2. 父目录创建未成功,但代码继续执行子目录创建
你的代码中,创建父目录userImagesDirectory时如果因为权限、父父目录不存在等原因失败,catch块只是输出警告就继续执行子目录创建。虽然这种情况通常会抛出ENOENT(父目录不存在)错误,但如果父目录路径包含符号链接指向已存在的文件,也可能触发EEXIST。
3. 符号链接导致的路径混淆
如果你的路径中包含符号链接,可能实际指向的是一个已存在的文件或目录,导致Node.js误判路径已存在。你可以用realpath命令查看路径的实际指向:
realpath /home/msh/Documents/arraba-api/app/build/plugin/images/images/5/profile
代码修复建议
方法1:添加recursive: true参数(最省心的方案)
Node.js的fs.mkdir(包括Promise版本)支持recursive: true选项,它会自动创建所有不存在的父目录,并且如果目标目录已存在(且是目录),会直接忽略,不会抛出错误。修改你的createDirectoryIfNotExists函数:
const createDirectoryIfNotExists = async ( dir, permission = true ) => { let output; try { output = await fsPromises.mkdir(dir, { mode: permission === true ? 0o775 : undefined, recursive: true // 新增递归创建选项 }); } catch (error) { // 只忽略「目录已存在」的情况,若存在同名文件则抛出错误 if (error.code !== 'EEXIST' || !(await fsPromises.stat(dir)).isDirectory()) { output = error.message; console.error('创建目录失败:', error); throw error; } else { console.warn('目录已存在:', dir); output = null; } } return output; };
这样不仅能一次性创建整个目录树,还能准确区分“目录已存在”和“同名文件存在”的场景。
方法2:在catch块中验证路径类型
当捕获到EEXIST错误时,先检查该路径是否为目录,再决定是否忽略:
catch (error) { if (error.code === 'EEXIST') { try { const stats = await fsPromises.stat(dir); if (stats.isDirectory()) { console.warn('目录已存在:', dir); output = null; } else { console.error('路径已存在,但不是目录:', dir); throw error; } } catch (statError) { console.error('检查路径状态失败:', statError); throw statError; } } else { console.error('创建目录失败:', error); output = error.message; throw error; } }
方法3:确保父目录创建成功后再处理子目录
避免因为父目录未创建成功,导致子目录创建触发异常:
const userDirectoryTreeCreation = async (userId) => { let userImagesDirectory = `${containerWorkDirectory}/${userId}`; let userProfileImagesDirectory = `${userImagesDirectory}/profile`; let userCarImagesDirectory = `${userImagesDirectory}/cars`; // 先确认父目录创建成功 const parentResult = await createDirectoryIfNotExists( userImagesDirectory, true ); if (parentResult && parentResult.includes('error')) { console.error('父目录创建失败:', parentResult); return; } await createDirectoryIfNotExists( userProfileImagesDirectory, true ); await createDirectoryIfNotExists( userCarImagesDirectory, true ); };
先按照上述步骤排查路径问题,再调整代码,应该就能解决这个异常了。
内容的提问来源于stack exchange,提问作者Pixel Coder

