CherryHQ/cherry-studio · error · Error

Failed to delete: ${error.message}

Error message

Failed to delete: ${error.message}

What it means

The catch-all for deletion failures that are neither ENOENT (handled at line 45) nor ENOTEMPTY (handled at line 68). It wraps any remaining NodeFileSystemError into 'Failed to delete: <message>'. Common underlying codes include EACCES/EPERM (permission), EBUSY (file in use on Windows), EROFS (read-only filesystem), or EMFILE (too many open files). The original error code is dropped — only message survives.

Source

Thrown at src/main/ai/mcp/servers/filesystem/tools/delete.ts:71

  // Perform deletion
  try {
    if (isDirectory) {
      if (recursive) {
        // Delete directory recursively
        await fs.rm(validPath, { recursive: true, force: true })
      } else {
        // Try to delete empty directory
        await fs.rmdir(validPath)
      }
    } else {
      // Delete file
      await fs.unlink(validPath)
    }
  } catch (error: any) {
    if (error.code === 'ENOTEMPTY') {
      throw new Error(`Directory not empty: ${targetPath}. Use recursive=true to delete non-empty directories.`)
    }
    throw new Error(`Failed to delete: ${error.message}`)
  }

  // Log the operation
  logger.info('Path deleted', {
    path: validPath,
    type: isDirectory ? 'directory' : 'file',
    recursive: isDirectory ? recursive : undefined
  })

  // Format output
  const itemType = isDirectory ? 'Directory' : 'File'
  const recursiveNote = isDirectory && recursive ? ' (recursive)' : ''

  return {
    content: [
      {
        type: 'text',
        text: `${itemType} deleted${recursiveNote}: ${relativePath}`

View on GitHub (pinned to 726446b54c)

Solutions

  1. Check filesystem permissions on the target and its parent directory (write+execute on parent needed for deletion).
  2. On Windows, ensure no process (including the Electron app itself) holds the file open.
  3. Preserve the error code in the message so EACCES vs EBUSY vs EROFS is diagnosable — the current message loses that detail.
  4. If the underlying cause is EMFILE, raise the file descriptor limit or reduce concurrent file operations.

Example fix

// before
throw new Error(`Failed to delete: ${error.message}`)

// after — keep the errno code for diagnosis
throw new Error(`Failed to delete (${error.code ?? 'UNKNOWN'}): ${error.message}`)
Defensive patterns

Strategy: try-catch

Type guard

// Classify the underlying filesystem error code to choose a remedy.
function isPermissionError(e: unknown): boolean {
  return e instanceof Error && /EACCES|EPERM/.test((e as any).code ?? '')
}

Try / catch

// Map fs error codes to actionable messages.
try {
  isDirectory ? await fs.rm(validPath, { recursive, force: true }) : await fs.unlink(validPath)
} catch (e: any) {
  if (e.code === 'ENOTEMPTY') throw new Error(`Directory not empty: ${targetPath}`)
  if (/EACCES|EPERM/.test(e.code)) throw new Error(`Permission denied deleting ${targetPath}`)
  if (e.code === 'EBUSY') throw new Error(`File in use: ${targetPath}`)
  throw new Error(`Failed to delete (${e.code}): ${e.message}`)
}

Prevention

When it happens

Trigger: The process lacks write/delete permission on the target; on Windows the file is open in another process or held by an antivirus; the target lives on a read-only mount; the file descriptor limit is exhausted.

Common situations: Files created by a different user and not chmod'd; Windows file locking; deleting from a mounted read-only snapshot; sandbox environments that forbid deletion outside an allowlist.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/84869ba81dad35d2. Report an issue: GitHub.