{"record":{"id":"6afb37db07633afb","repo":"can1357/oh-my-pi","slug":"path-is-not-a-file-patharg","errorCode":null,"errorMessage":"Path is not a file: ${pathArg}","messagePattern":"Path is not a file: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cursor.ts","lineNumber":355,"sourceCode":"\tif (refusal) {\n\t\treturn createToolResultMessage(toolCallId, toolName, buildToolErrorResult(refusal), true);\n\t}\n\n\toptions.emitEvent?.({ type: \"tool_execution_start\", toolCallId, toolName, args: { path: pathArg } });\n\n\tconst absolutePath = resolveToCwd(pathArg, options.getCwd?.() ?? options.cwd);\n\tlet isError = false;\n\tlet result: AgentToolResult<unknown>;\n\n\ttry {\n\t\tlet fileStat: fs.Stats | undefined;\n\t\ttry {\n\t\t\tfileStat = fs.statSync(absolutePath);\n\t\t} catch {\n\t\t\tthrow new Error(`File not found: ${pathArg}`);\n\t\t}\n\t\tif (!fileStat.isFile()) {\n\t\t\tthrow new Error(`Path is not a file: ${pathArg}`);\n\t\t}\n\n\t\tfs.rmSync(absolutePath);\n\n\t\tconst sizeText = fileStat.size ? ` (${fileStat.size} bytes)` : \"\";\n\t\tconst message = `Deleted ${pathArg}${sizeText}`;\n\t\tresult = { content: [{ type: \"text\", text: message }], details: {} };\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tresult = buildToolErrorResult(message);\n\t\tisError = true;\n\t}\n\n\toptions.emitEvent?.({ type: \"tool_execution_end\", toolCallId, toolName, result, isError });\n\treturn createToolResultMessage(toolCallId, toolName, result, isError);\n}\n\nfunction decodeToolCallId(toolCallId?: string): string {","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cursor.ts#L337-L373","documentation":"The delete tool only removes regular files. If stat succeeds but the entry is a directory, symlink-to-directory, socket, FIFO, or device, the operation refuses with this message rather than recursing or unlinking something unexpected.","triggerScenarios":"pathArg resolves to an existing directory (most common), a special file, or a symlink pointing at a directory, in the executeDelete path.","commonSituations":"Asking the agent to 'delete the build folder' through the file-delete tool instead of a shell command; passing a directory that was expected to be a file after a refactor.","solutions":["If you intend to remove a directory, use the bash/shell tool with `rm -r <dir>` instead of the file-delete tool.","Point pathArg at an individual regular file inside the directory.","Check what the path is with `ls -la <path>` / `stat <path>` before deleting."],"exampleFix":"// before\nawait execDelete(\"dist\");  // dist is a directory\n// after (shell tool)\nawait bash(\"rm -r dist\");","handlingStrategy":"validation","validationCode":"import { statSync } from \"node:fs\";\nconst s = statSync(absolutePath, { throwIfNoEntry: false });\nif (s && !s.isFile()) throw new Error(`${absolutePath} is not a regular file; use rm -r for directories`);\n","typeGuard":"function isFileStat(s: import(\"node:fs\").Stats | undefined): s is import(\"node:fs\").Stats & { isFile(): true } {\n  return !!s && s.isFile();\n}","tryCatchPattern":"try {\n  await execDelete(pathArg);\n} catch (e) {\n  if (String(e.message).startsWith(\"Path is not a file\")) {\n    // route directories to `rm -r` via the shell tool instead\n  } else throw e;\n}","preventionTips":["Check the entry type with stat before deleting.","Use the shell tool (`rm -r`) for directories; reserve the delete tool for files.","Don't assume a path's type from its name or extension."],"tags":["filesystem","tooling","validation"],"backgroundTag":"not-a-regular-file","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}