{"record":{"id":"84a16bdf8b17963d","repo":"apache/seatunnel","slug":"failed-to-change-working-directory-to-s-ftp-repl","errorCode":null,"errorMessage":"Failed to change working directory to %s, FTP reply code: %d, reply string: %s","messagePattern":"Failed to change working directory to (.+?), FTP reply code: (.+?), reply string: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java","lineNumber":748,"sourceCode":"                        String.format(\n                                \"Can't make directory for path %s since it is a file.\", absolute));\n            }\n            return true;\n        }\n\n        // Create parent directories if they don't exist\n        Path parent = absolute.getParent();\n        if (parent != null && !exists(client, parent)) {\n            mkdirs(client, parent, FsPermission.getDirDefault());\n        }\n\n        // Create the directory\n        String pathName = absolute.getName();\n        String parentDir = parent != null ? parent.toUri().getPath() : \"/\";\n\n        // Change to parent directory\n        if (!client.changeWorkingDirectory(parentDir)) {\n            throw new IOException(\n                    String.format(\n                            \"Failed to change working directory to %s, FTP reply code: %d, reply string: %s\",\n                            parentDir, client.getReplyCode(), client.getReplyString()));\n        }\n        // Create directory\n        boolean created = client.makeDirectory(pathName);\n        if (!created) {\n            // Double check if directory was actually created (some FTP servers don't return true)\n            if (!exists(client, absolute)) {\n                throw new IOException(\n                        String.format(\n                                \"Failed to create directory %s in %s, FTP reply code: %d, reply string: %s\",\n                                pathName,\n                                parentDir,\n                                client.getReplyCode(),\n                                client.getReplyString()));\n            }\n        }","sourceCodeStart":730,"sourceCodeEnd":766,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java#L730-L766","documentation":"Thrown when creating a directory on the FTP server: the client could not change its working directory (CWD) to the intended parent directory before issuing MKD, so the create is aborted. The message includes the parent path, FTP reply code, and reply string for diagnosis.","triggerScenarios":"fs.mkdirs(path) where the parent directory does not exist on the server, the user lacks execute/enter permission on it, or the CWD command is rejected by the server (path invalid, permission denied, connection issue).","commonSituations":"Creating deep nested output paths whose parent does not exist yet on the FTP server; FTP user confined to a home directory so absolute parents like /data are not enterable; typo'd base path in connector config; permission-restricted directories.","solutions":["Ensure the parent directory exists (create parents first or fs.mkdirs the full hierarchy in order)","Check FTP reply code/string in the error: 550 → permission/not-found, 530 → login issue","Verify the FTP user's home directory and permissions allow entering the parent path","Use paths relative to the FTP user's root instead of server-absolute paths","Test CWD to the parent manually with the same credentials"],"exampleFix":"// before\nfs.mkdirs(new Path(\"/data/output/2026/09\")); // /data/output missing\n// after\nfor (Path p : Arrays.asList(new Path(\"/data/output/2026\"), new Path(\"/data/output/2026/09\"))) {\n    if (!fs.exists(p)) {\n        fs.mkdirs(p);\n    }\n}","handlingStrategy":"validation","validationCode":"Path parent = path.getParent();\nif (!fs.exists(parent)) {\n    fs.mkdirs(parent); // create parents before the CWD-based create path\n}","typeGuard":null,"tryCatchPattern":"try {\n    fs.mkdirs(dir);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Failed to change working directory\")) {\n        // parse reply code from message: 550 → permission/not-found; fix parent path or perms\n    } else { throw e; }\n}","preventionTips":["Create parent directories hierarchically before creating deep paths","Prefer paths relative to the FTP user's root over server-absolute paths","Confirm the FTP user can CWD into the parent (permissions, home-dir scoping)","Test directory creation manually with the same credentials before production"],"tags":["ftp","mkdir","cwd","permissions"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}