{"record":{"id":"7bd5470d88a2003c","repo":"apache/iceberg","slug":"file-length-is-null","errorCode":null,"errorMessage":"File length is null","messagePattern":"File length is null","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/encryption/AesGcmInputFile.java","lineNumber":51,"sourceCode":"   * @deprecated will be removed in 2.0.0 This API does not receive file length, and is therefore\n   *     not safe\n   */\n  @Deprecated\n  public AesGcmInputFile(InputFile sourceFile, byte[] dataKey, byte[] fileAADPrefix) {\n    this(sourceFile, dataKey, fileAADPrefix, null);\n  }\n\n  public AesGcmInputFile(InputFile sourceFile, byte[] dataKey, byte[] fileAADPrefix, Long length) {\n    this.sourceFile = sourceFile;\n    this.dataKey = dataKey;\n    this.fileAADPrefix = fileAADPrefix;\n    this.encryptedLength = length;\n    this.plaintextLength = null;\n  }\n\n  private long encryptedLength() {\n    if (encryptedLength == null) {\n      throw new IllegalArgumentException(\"File length is null\");\n    }\n\n    return encryptedLength;\n  }\n\n  @Override\n  public long getLength() {\n    if (plaintextLength == null) {\n      // Presumes all streams use hard-coded plaintext block size.\n      plaintextLength = AesGcmInputStream.calculatePlaintextLength(encryptedLength());\n    }\n\n    return plaintextLength;\n  }\n\n  @Override\n  public SeekableInputStream newStream() {\n    long ciphertextLength = encryptedLength();","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/encryption/AesGcmInputFile.java#L33-L69","documentation":"AesGcmInputFile.encryptedLength() returns the encrypted file length, but if the file was constructed without a known encrypted length (the constructor variant that leaves encryptedLength null), it throws IllegalArgumentException. Encrypted-length-dependent operations (like producing a positioned stream) cannot proceed without it.","triggerScenarios":"Creating an AesGcmInputFile via the constructor that omits the encrypted length, then invoking a path that calls encryptedLength() (e.g. newStream or length calculations that need the encrypted size).","commonSituations":"Wrapping files whose length is not knowable upfront (e.g. non-seekable or streaming sources) into AesGcmInputFile, then treating them as seekable encrypted inputs.","solutions":["Construct AesGcmInputFile with the encrypted file length (the constructor variant that sets it)","Ensure the underlying FileIO can report the file size before opening the encrypted input file","Guard call sites: check that length is known before requesting streams that depend on encrypted length"],"exampleFix":"// before\nnew AesGcmInputFile(rawFile, key, aad); // encrypted length unknown\n// after\nnew AesGcmInputFile(rawFile, key, aad, rawFile.getLength());","handlingStrategy":"validation","validationCode":"if (rawFile.getLength() <= 0) { throw new IllegalArgumentException(\"Encrypted length required for AesGcmInputFile\"); }","typeGuard":"boolean hasKnownLength(InputFile f) { try { return f.getLength() > 0; } catch (Exception e) { return false; } }","tryCatchPattern":"try { stream = aesGcmInputFile.newStream(); } catch (IllegalArgumentException e) { /* length missing: obtain it and rebuild the file */ }","preventionTips":["Always pass the encrypted file length when constructing AesGcmInputFile","Ensure the FileIO supports getLength() for the storage backend","Do not wrap streaming/non-seekable sources as seekable encrypted input files"],"tags":["java","encryption","io"],"backgroundTag":"missing-required-argument","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}