{"record":{"id":"25ca11a6cbcf46d2","repo":"stablyai/orca","slug":"cannot-write-to-a-directory","errorCode":null,"errorMessage":"Cannot write to a directory","messagePattern":"Cannot write to a directory","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/filesystem.ts","lineNumber":867,"sourceCode":"      _event,\n      args: { filePath: string; content: string; connectionId?: string } & SshMutationExpectation\n    ): Promise<void> => {\n      assertSshMutationExpectation(\n        args.connectionId,\n        args.expectedSshTargetId,\n        args.expectedSshConnectionGeneration,\n        args.expectedExecutionHostId\n      )\n      if (args.connectionId) {\n        const provider = requireSshFilesystemProvider(args.connectionId)\n        return provider.writeFile(args.filePath, args.content)\n      }\n      const filePath = await resolveAuthorizedPath(args.filePath, store)\n\n      try {\n        const fileStats = await lstat(filePath)\n        if (fileStats.isDirectory()) {\n          throw new Error('Cannot write to a directory')\n        }\n      } catch (error) {\n        if (!isENOENT(error)) {\n          throw error\n        }\n      }\n\n      await writeFile(filePath, args.content, 'utf-8')\n    }\n  )\n\n  ipcMain.handle(\n    'fs:deletePath',\n    async (\n      _event,\n      args: {\n        targetPath: string\n        connectionId?: string","sourceCodeStart":849,"sourceCodeEnd":885,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/filesystem.ts#L849-L885","documentation":"Thrown by the local-write branch of a writeFile IPC handler (src/main/ipc/filesystem.ts:867). After resolveAuthorizedPath returns a path, the handler lstats it; if it is a directory, writing file content is rejected. ENOENT is allowed (creating a new file) and other stat errors are rethrown.","triggerScenarios":"Calling the write handler with a filePath that resolves to an existing directory: a trailing slash, a bare folder path like '/repo/src', or a path where a directory of the same name already exists.","commonSituations":"Path normalization bug appending '/' or joining incorrectly; a 'save file' flow that accepted a directory picker result; resolveAuthorizedPath resolving a symlinked folder; user typing a folder name in a save dialog.","solutions":["Append an actual file name to the directory path before writing.","Strip trailing slashes from filePath before invoking the handler.","If writing inside the directory is intended, use path.join(dirPath, fileName)."],"exampleFix":"// before: target resolves to a directory\nawait invoke('fs:writeFile', { filePath: '/repo/src', content })\n\n// after: target is a file inside the directory\nawait invoke('fs:writeFile', { filePath: '/repo/src/notes.md', content })","handlingStrategy":"validation","validationCode":"import { lstat } from 'node:fs/promises'\nasync function assertIsFilePath(p: string): Promise<void> {\n  const s = await lstat(p).catch(() => null)\n  if (s?.isDirectory()) throw new Error(`Refusing to write: ${p} is a directory`)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize filePath to strip trailing slashes before writing.","When the user picks a destination, reject directory entries.","Join directory + filename explicitly rather than writing to the bare folder path."],"tags":["filesystem","validation","paths"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}