{"record":{"id":"7e38d4558dfc2cf7","repo":"apache/iceberg","slug":"file-length-unknown-creating-an-aesgcminputfile-i","errorCode":null,"errorMessage":"File length unknown, creating an AesGcmInputFile is not safe","messagePattern":"File length unknown, creating an AesGcmInputFile is not safe","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/encryption/AesGcmOutputFile.java","lineNumber":53,"sourceCode":"\n  @Override\n  public PositionOutputStream create() {\n    return new AesGcmOutputStream(targetFile.create(), dataKey, fileAADPrefix);\n  }\n\n  @Override\n  public PositionOutputStream createOrOverwrite() {\n    return new AesGcmOutputStream(targetFile.createOrOverwrite(), dataKey, fileAADPrefix);\n  }\n\n  @Override\n  public String location() {\n    return targetFile.location();\n  }\n\n  @Override\n  public InputFile toInputFile() {\n    throw new IllegalStateException(\"File length unknown, creating an AesGcmInputFile is not safe\");\n  }\n}\n","sourceCodeStart":35,"sourceCodeEnd":56,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/encryption/AesGcmOutputFile.java#L35-L56","documentation":"AesGcmOutputFile.toInputFile() always throws IllegalStateException because an encrypted output file's length is unknown until it is closed and committed; creating an InputFile view would be unsafe. This is an intentional guard, not a recoverable failure.","triggerScenarios":"Calling toInputFile() on an AesGcmOutputFile, e.g. generic code that converts any OutputFile to an InputFile (such as overwrite/commit plumbing that immediately re-reads the written file).","commonSituations":"Frameworks that unconditionally call toInputFile() on freshly written outputs, or code that tries to read an encrypted file while it is still being written.","solutions":["Close/complete the output and obtain an InputFile from the underlying FileIO using the known final file length (e.g. io.newInputFile(location)) instead of toInputFile()","Delay any read of the encrypted file until after the write is finished and its length is known","Restructure the commit flow to use the resulting DataFile/DeleteFile metadata (with file size) rather than converting the output file"],"exampleFix":"// before\nInputFile in = aesGcmOutputFile.toInputFile();\n// after\noutputFile.close(); // complete the write first\nInputFile in = fileIO.newInputFile(location);","handlingStrategy":"fallback","validationCode":"// cannot be validated on the object itself; ensure write is complete before reading\nif (!outputComplete) { throw new IllegalStateException(\"Output file not finalized; cannot read\"); }","typeGuard":null,"tryCatchPattern":"try { return out.toInputFile(); } catch (IllegalStateException e) { return fileIO.newInputFile(out.location()); /* after close */ }","preventionTips":["Never read an encrypted file before its write is closed and length committed","Convert outputs to inputs via the FileIO with the final location and size, not via toInputFile()","Design commit flows around DataFile/DeleteFile metadata rather than live OutputFile handles"],"tags":["java","encryption","io"],"backgroundTag":"invalid-state-transition","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"}