apache/iceberg · error · RuntimeException
Version byte - end of stream reached
Error message
Version byte - end of stream reached
What it means
After reading the version byte, decode checks whether stream.read() returned -1 (which becomes a negative byte). If so, the stream was empty or already exhausted, meaning the key metadata blob contains no data at all.
Source
Thrown at core/src/main/java/org/apache/iceberg/encryption/KeyMetadataDecoder.java:56
* <p>The {@code readSchemaVersion} is as used the version of the expected (read) schema. Datum
* instances created by this class will are described by the expected schema.
*/
KeyMetadataDecoder(byte readSchemaVersion) {
this.readSchema = StandardKeyMetadata.supportedSchemaVersions().get(readSchemaVersion);
}
@Override
public StandardKeyMetadata decode(InputStream stream, StandardKeyMetadata reuse) {
byte writeSchemaVersion;
try {
writeSchemaVersion = (byte) stream.read();
} catch (IOException e) {
throw new UncheckedIOException("Failed to read the version byte", e);
}
if (writeSchemaVersion < 0) {
throw new RuntimeException("Version byte - end of stream reached");
}
Schema writeSchema = StandardKeyMetadata.supportedAvroSchemaVersions().get(writeSchemaVersion);
if (writeSchema == null) {
throw new UnsupportedOperationException(
"Cannot resolve schema for version: " + writeSchemaVersion);
}
RawDecoder<StandardKeyMetadata> decoder = decoders.get(writeSchemaVersion);
if (decoder == null) {
decoder = RawDecoder.create(readSchema, GenericAvroReader::create, writeSchema);
decoders.put(writeSchemaVersion, decoder);
}
return decoder.decode(stream, reuse);View on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure the key metadata buffer/stream is non-empty and positioned at the start before decoding
- Regenerate the encrypted file's key metadata if it was written empty
- Rewind or re-wrap the buffer (duplicate() and flip) before passing it to decode
Example fix
// before
decoder.decode(ByteBuffer.allocate(0)); // RuntimeException
// after
ByteBuffer km = ...; // non-empty buffer with encoded key metadata
if (km != null && km.hasRemaining()) { decoder.decode(km); } Defensive patterns
Strategy: validation
Validate before calling
if (buffer == null || buffer.remaining() == 0) {
throw new IllegalArgumentException("Key metadata buffer is empty");
} Type guard
boolean hasKeyMetadata(ByteBuffer b) { return b != null && b.remaining() >= 1; } Try / catch
try { return decoder.decode(stream, null); }
catch (RuntimeException e) {
if (e.getMessage().contains("end of stream")) { /* empty metadata handling */ }
throw e;
} Prevention
- Never decode zero-length or fully consumed buffers
- duplicate() and reset position before decoding ByteBuffers
- Treat empty key metadata as a writer bug and investigate the producing code path
When it happens
Trigger: Calling KeyMetadataDecoder.decode with an empty InputStream, or a ByteBuffer/stream positioned at EOF, so stream.read() returns -1 on the first byte.
Common situations: Passing a zero-length key metadata buffer from a freshly created/never-written encrypted file; decoding an empty byte array; stream already consumed by a prior read.
Related errors
- Failed to read the version byte
- Cannot resolve schema for version: ${writeSchemaVersion}
- Null key metadata buffer
- Failed to parse envelope encryption metadata
- Failed to close encryption manager
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8b2a83ed115b8e44.
Report an issue: GitHub.