{"record":{"id":"5c7214c713b87f80","repo":"CherryHQ/cherry-studio","slug":"failed-to-create-parent-directory-error-message","errorCode":null,"errorMessage":"Failed to create parent directory: ${error.message}","messagePattern":"Failed to create parent directory: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/servers/filesystem/tools/write.ts","lineNumber":43,"sourceCode":"}\n\n// Handler implementation\nexport async function handleWriteTool(args: unknown, baseDir: string) {\n  const parsed = WriteToolSchema.safeParse(args)\n  if (!parsed.success) {\n    throw new Error(`Invalid arguments for write: ${parsed.error}`)\n  }\n\n  const filePath = parsed.data.file_path\n  const validPath = await validatePath(filePath, baseDir)\n\n  // Create parent directory if it doesn't exist\n  const parentDir = path.dirname(validPath)\n  try {\n    await fs.mkdir(parentDir, { recursive: true })\n  } catch (error: any) {\n    if (error.code !== 'EEXIST') {\n      throw new Error(`Failed to create parent directory: ${error.message}`)\n    }\n  }\n\n  // Check if file exists (for logging)\n  let isOverwrite = false\n  try {\n    await fs.stat(validPath)\n    isOverwrite = true\n  } catch {\n    // File doesn't exist, that's fine\n  }\n\n  // Write the file\n  try {\n    await fs.writeFile(validPath, parsed.data.content, 'utf-8')\n  } catch (error: any) {\n    throw new Error(`Failed to write file: ${error.message}`)\n  }","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/filesystem/tools/write.ts#L25-L61","documentation":"Thrown by the write tool when fs.mkdir(parentDir, {recursive:true}) fails with an error code other than EEXIST. EEXIST is intentionally swallowed, but any other failure (EACCES permission denied, ENAMETOOLONG, ENOTDIR when a path component is a file not a directory, EROFS on read-only filesystem, ENOSPC) is wrapped and re-thrown, aborting the write before the file is created.","triggerScenarios":"Writing to a path whose parent chain crosses a file (ENOTDIR), into a directory the process lacks permission to create (EACCES), onto a read-only volume (EROFS), with a path longer than OS limits (ENAMETOOLONG), or when the disk is out of space/inodes at mkdir time.","commonSituations":"baseDir misconfigured to a read-only mount; parent path accidentally contains a filename segment; sandboxed Electron process with restricted filesystem ACLs; very deep nested paths generated programmatically; cross-device path after a config change.","solutions":["Confirm the parent directory is writable by the process and not on a read-only filesystem.","Check that no path segment is a regular file (ENOTDIR) by listing the parent chain.","Shorten overly deep paths or relax the sandbox/ACL for the workspace root.","Inspect error.message (it carries the underlying errno/code) to identify EACCES vs EROFS vs ENOTDIR."],"exampleFix":"// before: baseDir on read-only mount\nawait handleWriteTool({ file_path: '/readonly/out.txt', content: 'x' }, baseDir) // throws: Failed to create parent directory\n\n// after: point baseDir at a writable workspace\nawait handleWriteTool({ file_path: '/workspace/out.txt', content: 'x' }, writableBaseDir)","handlingStrategy":"try-catch","validationCode":"import fs from 'fs/promises'\nasync function ensureParentWritable(filePath: string): Promise<void> {\n  const parent = path.dirname(filePath)\n  await fs.mkdir(parent, { recursive: true }) // surface errors early\n  await fs.access(parent, fs.constants.W_OK)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await handleWriteTool(args, baseDir)\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e)\n  if (msg.startsWith('Failed to create parent directory')) {\n    // inspect errno: EACCES -> permissions, EROFS -> read-only, ENOTDIR -> path-segment-is-file\n  } else throw e\n}","preventionTips":["Confirm the workspace root is on a writable filesystem before enabling the write tool.","Avoid building paths with arbitrary user segments that can collide with existing files (ENOTDIR).","Watch for sandbox/ACL changes after app or OS updates."],"tags":["filesystem","permissions","mcp","write-tool","mkdir"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}