{"record":{"id":"609455f792b66339","repo":"CherryHQ/cherry-studio","slug":"path-not-found-targetpath","errorCode":null,"errorMessage":"Path not found: ${targetPath}","messagePattern":"Path not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ai/mcp/servers/filesystem/tools/delete.ts","lineNumber":45,"sourceCode":"\n// Handler implementation\nexport async function handleDeleteTool(args: unknown, baseDir: string) {\n  const parsed = DeleteToolSchema.safeParse(args)\n  if (!parsed.success) {\n    throw new Error(`Invalid arguments for delete: ${parsed.error}`)\n  }\n\n  const targetPath = parsed.data.path\n  const validPath = await validatePath(targetPath, baseDir)\n  const recursive = parsed.data.recursive || false\n\n  // Check if path exists and get stats\n  let stats\n  try {\n    stats = await fs.stat(validPath)\n  } catch (error: any) {\n    if (error.code === 'ENOENT') {\n      throw new Error(`Path not found: ${targetPath}`)\n    }\n    throw error\n  }\n\n  const isDirectory = stats.isDirectory()\n  const relativePath = path.relative(baseDir, validPath)\n\n  // Perform deletion\n  try {\n    if (isDirectory) {\n      if (recursive) {\n        // Delete directory recursively\n        await fs.rm(validPath, { recursive: true, force: true })\n      } else {\n        // Try to delete empty directory\n        await fs.rmdir(validPath)\n      }\n    } else {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/filesystem/tools/delete.ts#L27-L63","documentation":"fs.stat on the validated deletion target rejected with code ENOENT — the path resolved inside the workspace root but nothing exists there. Thrown after validatePath succeeds, so this is purely an on-disk existence check, not a sandboxing failure. The user-facing path (targetPath) is used in the message, not the resolved absolute path.","triggerScenarios":"The caller passed a path to a file/directory that has already been deleted, was never created, or was misspelled. Also fires on TOCTOU races where the entry is removed between listing and deletion.","commonSituations":"A model deleting a file it previously read but that a concurrent process removed; a stale path from an earlier session; a relative-vs-absolute confusion that validatePath accepted but points at an empty slot.","solutions":["Confirm the path still exists immediately before calling delete — list the parent directory first.","If the path was just created in the same flow, watch for async ordering that deletes before creation completes.","Treat a missing target as idempotent success if that matches the tool's semantics — swallow ENOENT instead of throwing."],"exampleFix":"// before\ntry {\n  stats = await fs.stat(validPath)\n} catch (error: any) {\n  if (error.code === 'ENOENT') {\n    throw new Error(`Path not found: ${targetPath}`)\n  }\n  throw error\n}\n\n// after — optional idempotent mode for delete-if-exists semantics\nif (options.idempotent) {\n  return { content: [{ type: 'text', text: `Already absent: ${relativePath}` }] }\n}\nthrow new Error(`Path not found: ${targetPath}`)","handlingStrategy":"validation","validationCode":"// Check existence before attempting deletion to give a clearer message.\nimport { stat } from 'fs/promises'\nasync function assertExists(p: string): Promise<void> {\n  try { await stat(p) } catch { throw new Error(`Path not found: ${p}`) }\n}","typeGuard":null,"tryCatchPattern":"// Treat ENOENT as idempotent success if 'delete-if-exists' semantics are desired.\ntry {\n  stats = await fs.stat(validPath)\n} catch (e: any) {\n  if (e.code === 'ENOENT' && options.idempotent) return alreadyAbsentResult\n  if (e.code === 'ENOENT') throw new Error(`Path not found: ${targetPath}`)\n  throw e\n}","preventionTips":["List the parent directory before deleting to confirm the entry exists.","Watch for TOCTOU races in concurrent flows that create and delete the same path.","Consider idempotent delete semantics if your tool contract allows it.","Use absolute paths to avoid resolution surprises."],"tags":["filesystem","enoent","delete","mcp-tool"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}