{"record":{"id":"3dd0a145b2e88d15","repo":"xpipe-io/xpipe","slug":"target-path-is-not-a-directory","errorCode":null,"errorMessage":"Target ${path} is not a directory","messagePattern":"Target (.+?) is not a directory","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferOperation.java","lineNumber":167,"sourceCode":"            return false;\n        }\n\n        var same = files.getFirst().getFileSystem().equals(target.getFileSystem());\n        var doesMove = transferMode == BrowserFileTransferMode.MOVE\n                || (same && transferMode == BrowserFileTransferMode.NORMAL);\n        return doesMove;\n    }\n\n    public void execute() throws Exception {\n        if (files.isEmpty()) {\n            updateProgress(null);\n            return;\n        }\n\n        reinitFileSystemsIfNeeded();\n\n        if (target.getKind() != FileKind.DIRECTORY) {\n            throw new IllegalStateException(\"Target \" + target.getPath() + \" is not a directory\");\n        }\n\n        BrowserFileSystemHelper.validateDirectoryPath(target.getFileSystem(), target.getPath(), true);\n\n        cancelled.set(false);\n\n        var same = files.getFirst().getFileSystem().equals(target.getFileSystem());\n        var doesMove = transferMode == BrowserFileTransferMode.MOVE\n                || (same && transferMode == BrowserFileTransferMode.NORMAL);\n        try {\n            for (var file : files) {\n                if (cancelled()) {\n                    break;\n                }\n\n                if (same) {\n                    handleSingleOnSameFileSystem(file);\n                } else {","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/xpipe-io/xpipe/blob/d85ca821baa46092a320ebb13546d7240adb74f8/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferOperation.java#L149-L185","documentation":"Thrown by BrowserFileTransferOperation.execute when the transfer target BrowserEntry is not a directory. Transfers (move/copy/paste) require a directory target, so the operation aborts with an IllegalStateException before validation proceeds.","triggerScenarios":"Initiating a file paste/move/copy in the XPipe browser while the selected target entry is a file rather than a directory, often after the target was deleted/re-created or a stale selection was used.","commonSituations":"Stale browser selection after a refresh, programmatically driving transfers with a file path as target, or confusing 'transfer into this file's parent' semantics.","solutions":["Select a directory as the transfer target","Refresh the browser and re-select the target to clear stale entries","In code, check entry.getKind() == FileKind.DIRECTORY before executing the transfer","If targeting a file's location, resolve its parent directory first"],"exampleFix":"// before\ntransfer(targetFileEntry, files) // kind = FILE\n// after\nif (target.getKind() == FileKind.DIRECTORY) {\n  executeTransfer(target, files);\n}","handlingStrategy":"validation","validationCode":"function assertDirectoryTarget(entry) {\n  if (entry.kind !== 'directory') {\n    throw new Error(`Target ${entry.path} is not a directory`);\n  }\n}\n// call before executing a browser transfer","typeGuard":"function isDirectoryEntry(entry) {\n  return entry && entry.kind === 'directory';\n}","tryCatchPattern":"try {\n  op.execute(target, files);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('is not a directory')) {\n    // re-select a directory target and retry\n  }\n}","preventionTips":["Refresh the browser before programmatic transfers to avoid stale selections","Check FileKind before targeting an entry","Resolve a file target to its parent directory"],"tags":["browser","filesystem","transfer"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"d85ca821baa46092a320ebb13546d7240adb74f8","analyzedAt":"2026-09-06T14:30:08.251Z","contentChangedAt":"2026-09-06T14:30:08.251Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}