{"record":{"id":"07785864fa124bee","repo":"apache/seatunnel","slug":"skipped-skipped-unparseable-ftp-listing-entries","errorCode":null,"errorMessage":"Skipped ${skipped} unparseable FTP listing entries under ${mask(absolute)}","messagePattern":"Skipped (.+?) unparseable FTP listing entries under (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-file/connector-file-ftp/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/ftp/system/SeaTunnelFTPFileSystem.java","lineNumber":548,"sourceCode":"            String previousDirectory = client.printWorkingDirectory();\n            if (!client.changeWorkingDirectory(absolute.toUri().getPath())) {\n                throw new FileNotFoundException(\"FTP directory does not exist: \" + mask(absolute));\n            }\n            Throwable failure = null;\n            try {\n                FTPListParseEngine engine = client.initiateListParsing();\n                if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {\n                    throw new IOException(\n                            \"FTP LIST failed for path=\"\n                                    + mask(absolute)\n                                    + \", replyCode=\"\n                                    + client.getReplyCode());\n                }\n                while (engine.hasNext()) {\n                    FTPFile[] files = engine.getNext(PAGE_SIZE);\n                    int skipped = emitFileStatuses(files, absolute, consumer);\n                    if (skipped > 0) {\n                        LOG.warn(\n                                \"Skipped \"\n                                        + skipped\n                                        + \" unparseable FTP listing entries under \"\n                                        + mask(absolute));\n                    }\n                }\n            } catch (IOException | RuntimeException | Error e) {\n                failure = e;\n                throw e;\n            } finally {\n                if (!client.changeWorkingDirectory(previousDirectory)) {\n                    IOException restoreFailure =\n                            new IOException(\n                                    \"Failed to restore FTP working directory, replyCode=\"\n                                            + client.getReplyCode());\n                    if (failure != null) {\n                        failure.addSuppressed(restoreFailure);\n                    } else {","sourceCodeStart":530,"sourceCodeEnd":566,"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#L530-L566","documentation":"While paginating a recursive FTP listing, list() calls emitFileStatuses for each page of FTPFile entries; entries that cannot be parsed into SeaTunnel FileStatus objects (malformed raw listing lines, nulls, unsupported types) are skipped and counted. When any were skipped, this warning names how many and under which (masked) directory. The listing continues with the parseable entries; it is informational, not fatal.","triggerScenarios":"During list(), a page from the FTPListingEngine (engine.getNext(PAGE_SIZE)) contains FTPFile entries that emitFileStatuses cannot map — e.g. FTPFile with null/invalid name, unknown or raw type, or entries the server's LIST output produced that the parser could not normalize.","commonSituations":"Non-standard FTP server LIST formats (unusual MLSD/LIST output the commons-net parser mangles); symbolic links or special files (devices, sockets) on the FTP server; filenames with exotic encodings or embedded newlines; permission-locked directories returning degenerate entries.","solutions":["Inspect the logged count and directory, then list that directory manually (ftp/ls) to identify the unparseable entries (symlinks, special files, odd encodings).","Prefer MLSD over LIST if the server supports it, or configure the FTP client's parser so listing lines are parsed correctly.","Rename or remove problem entries (special files, files with broken encodings) on the FTP server.","If the skipped files are not needed for the job, treat this as expected noise; otherwise confirm required files appear among the emitted statuses."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight: probe the directory listing yourself before the job and inspect raw entries\nFTPClient c = /* connected client */;\nFTPFile[] files = c.listFiles(path);\nfor (FTPFile f : files) {\n    if (f == null || f.getName() == null || f.getType() == FTPFile.UNKNOWN_TYPE) {\n        System.out.println(\"Unparseable entry under \" + path);\n    }\n}","typeGuard":null,"tryCatchPattern":"// Skipped entries are only warned; guard downstream consumers against missing paths:\ntry {\n    FileStatus status = filesystem.getFileStatus(new Path(target));\n} catch (IOException e) {\n    // file may have been one of the skipped/unparseable entries\n    LOG.warn(\"Target not listed by FTP: \" + target, e);\n}","preventionTips":["Avoid special files, symlinks, or non-regular entries on FTP paths consumed by the job","Use consistent filename encodings (UTF-8) on the FTP server","Verify the server's LIST output parses correctly with a manual session before production","Re-check important paths with getFileStatus if a listing warning names that directory"],"tags":["ftp","listing","parsing","listing-parsing"],"backgroundTag":"unexpected-response-shape","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}