{"record":{"id":"ec4c4b4d72a274d5","repo":"apache/hadoop","slug":"s-is-not-appendable-because-append-non-existed-ob","errorCode":null,"errorMessage":"%s is not appendable because append non-existed object with zero byte is not supported.","messagePattern":"(.+?) is not appendable because append non-existed object with zero byte is not supported\\.","errorType":"exception","errorClass":"NotAppendableException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-tos/src/main/java/org/apache/hadoop/fs/tosfs/object/FileStore.java","lineNumber":187,"sourceCode":"    }\n  }\n\n  @Override\n  public byte[] put(String key, InputStreamProvider streamProvider, long contentLength) {\n    Preconditions.checkArgument(!Strings.isNullOrEmpty(key), \"Key should not be empty.\");\n    File destFile = path(encode(key)).toFile();\n    copyInputStreamToFile(streamProvider.newStream(), destFile, contentLength);\n\n    return ObjectInfo.isDir(key) ? Constants.MAGIC_CHECKSUM : getFileChecksum(destFile.toPath());\n  }\n\n  @Override\n  public byte[] append(String key, InputStreamProvider streamProvider, long contentLength) {\n    Preconditions.checkArgument(!Strings.isNullOrEmpty(key), \"Key should not be empty.\");\n    File destFile = path(encode(key)).toFile();\n    if (!destFile.exists()) {\n      if (contentLength == 0) {\n        throw new NotAppendableException(String.format(\n            \"%s is not appendable because append non-existed object with \"\n                + \"zero byte is not supported.\", key));\n      }\n      return put(key, streamProvider, contentLength);\n    } else {\n      appendInputStreamToFile(streamProvider.newStream(), destFile, contentLength);\n      return ObjectInfo.isDir(key) ? Constants.MAGIC_CHECKSUM : getFileChecksum(destFile.toPath());\n    }\n  }\n\n  private static File createTmpFile(File destFile) {\n    String tmpFilename = \".tmp.\" + UUIDUtils.random();\n    File file = new File(destFile.getParentFile(), tmpFilename);\n\n    try {\n      if (!file.exists() && !file.createNewFile()) {\n        throw new RuntimeException(\"failed to create tmp file\");\n      }","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-tos/src/main/java/org/apache/hadoop/fs/tosfs/object/FileStore.java#L169-L205","documentation":"FileStore.append() refuses to append to a key that has no backing file when the declared contentLength is zero: appending zero bytes to a nonexistent object would have to create an empty file, which this local object-store emulation chooses not to support. It throws the typed NotAppendableException so callers can distinguish this case from other failures.","triggerScenarios":"storage.append(key, streamProvider, 0) (or append(key, bytes, 0, 0)) when no object exists at key — e.g. a flush of an empty buffer opening a new file, or a caller that initializes files by appending an empty chunk before writing data.","commonSituations":"OutputStream implementations that call append() on first write even when nothing has been buffered yet; HDFS-style append semantics ported to the filestore where create() is expected to happen implicitly; directory-marker keys being appended with zero length.","solutions":["Create the object first with put(key, streamProvider, 0) (zero-length put is supported) and append subsequent chunks","Skip the append entirely when there is nothing to write: only call append when contentLength > 0 or the object already exists","Catch the typed NotAppendableException and fall back to put() for the first chunk"],"exampleFix":"// before\nstorage.append(key, () -> new ByteArrayInputStream(new byte[0]), 0); // key absent -> NotAppendableException\n// after\nif (storage.objectStatus(key) == null) {\n  storage.put(key, () -> new ByteArrayInputStream(new byte[0]), 0); // create explicitly\n} else {\n  storage.append(key, () -> new ByteArrayInputStream(new byte[0]), 0);\n}","handlingStrategy":"validation","validationCode":"boolean exists = storage.objectStatus(key) != null;\nif (!exists && contentLength == 0) {\n  storage.put(key, streamProvider, 0); // zero-length put creates the object\n} else {\n  storage.append(key, streamProvider, contentLength);\n}","typeGuard":null,"tryCatchPattern":"try {\n  storage.append(key, streamProvider, contentLength);\n} catch (org.apache.hadoop.fs.tosfs.object.exceptions.NotAppendableException e) {\n  // first chunk of a new object: create it, then append the rest\n  storage.put(key, streamProvider, contentLength);\n}","preventionTips":["Create objects with put() and use append() only for subsequent chunks of existing objects","Skip write calls entirely when the buffer is empty — never append zero bytes to open a file","Buffer output and flush only when data exists (len > 0) or the object already exists","Write tests covering the first-flush-empty case for any custom OutputStream built on ObjectStorage"],"tags":["hadoop","tos","filestore","append","object-storage"],"backgroundTag":"zero-length-append-unsupported","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}