{"record":{"id":"4f1b35edbfa3c870","repo":"apache/hadoop","slug":"append-is-not-supported-by-ftpfilesystem","errorCode":null,"errorMessage":"Append is not supported by FTPFileSystem","messagePattern":"Append is not supported by FTPFileSystem","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPFileSystem.java","lineNumber":381,"sourceCode":"        if (!client.isConnected()) {\n          throw new FTPException(\"Client not connected\");\n        }\n        boolean cmdCompleted = client.completePendingCommand();\n        disconnect(client);\n        if (!cmdCompleted) {\n          throw new FTPException(\"Could not complete transfer, Reply Code - \"\n              + client.getReplyCode());\n        }\n      }\n    };\n    return fos;\n  }\n\n  /** This optional operation is not yet supported. */\n  @Override\n  public FSDataOutputStream append(Path f, int bufferSize,\n      Progressable progress) throws IOException {\n    throw new UnsupportedOperationException(\"Append is not supported \"\n        + \"by FTPFileSystem\");\n  }\n  \n  /**\n   * Convenience method, so that we don't open a new connection when using this\n   * method from within another method. Otherwise every API invocation incurs\n   * the overhead of opening/closing a TCP connection.\n   * @throws IOException on IO problems other than FileNotFoundException\n   */\n  private boolean exists(FTPClient client, Path file) throws IOException {\n    try {\n      getFileStatus(client, file);\n      return true;\n    } catch (FileNotFoundException fnfe) {\n      return false;\n    }\n  }\n","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ftp/FTPFileSystem.java#L363-L399","documentation":"FTPFileSystem does not implement append(): per the FileSystem contract append is optional, and this implementation always throws UnsupportedOperationException. FTP's STOR-based write model used here has no server-side append.","triggerScenarios":"Any fs.append(path) or fs.append(path, bufferSize) call on an ftp:// path — directly or through frameworks that rely on append (output-commit recovery, log tailing, append-based writers).","commonSituations":"Portable code that works on HDFS or s3a breaking when pointed at ftp://; frameworks probing append support at runtime; migration from HDFS to FTP-backed storage.","solutions":["Rewrite instead of append: read (or regenerate) the full content, concatenate locally, then fs.create(path, true) and write everything","Use a filesystem that supports append (HDFS) for append-based workloads","Branch at runtime on the scheme (fs.getScheme().equals(\"ftp\")) or catch UnsupportedOperationException to pick the rewrite strategy"],"exampleFix":"// before\nFSDataOutputStream out = fs.append(path); // UnsupportedOperationException\n\n// after - append by rewrite\nbyte[] existing = new byte[0];\nif (fs.exists(path)) {\n  try (FSDataInputStream in = fs.open(path)) {\n    existing = IOUtils.toByteArray(in);\n  }\n}\ntry (FSDataOutputStream out = fs.create(path, true)) {\n  out.write(existing);\n  out.write(extraBytes);\n}","handlingStrategy":"fallback","validationCode":"boolean canAppend = !\"ftp\".equals(fs.getScheme());\nif (!canAppend) {\n  // use the rewrite path instead of fs.append()\n}","typeGuard":null,"tryCatchPattern":"try {\n  out = fs.append(path);\n} catch (UnsupportedOperationException e) {\n  // fallback: read + rewrite\n  out = rewriteWith(path, extraBytes, fs);\n}","preventionTips":["Probe append support once per filesystem scheme and cache the decision","Design writers to create-or-rewrite rather than append when the scheme may be ftp","Prefer HDFS for workloads that genuinely require append semantics"],"tags":["ftp","append","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}