apache/iceberg · error · ParquetDecodingException
Failed to read a byte
Error message
Failed to read a byte
What it means
Thrown by ValuesAsBytesReader.getByte() when the underlying values InputStream throws an IOException while reading the next byte during Parquet value decoding. The library wraps the checked IOException in a ParquetDecodingException because decoding happens inside reader loops that do not declare checked exceptions. It almost always indicates truncated or corrupt page data rather than a data-type problem.
Source
Thrown at parquet/src/main/java/org/apache/iceberg/parquet/ValuesAsBytesReader.java:109
/** Returns 1 if true, 0 otherwise. */
public final int readBooleanAsInt() {
if (bitOffset == 0) {
currentByte = getByte();
}
int value = (currentByte & (1 << bitOffset)) >> bitOffset;
bitOffset += 1;
if (bitOffset == 8) {
bitOffset = 0;
}
return value;
}
private byte getByte() {
try {
return (byte) valuesInputStream.read();
} catch (IOException e) {
throw new ParquetDecodingException("Failed to read a byte", e);
}
}
}
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Verify the Parquet file is complete and not truncated (check file size vs manifest/expected length); re-copy or re-download the file.
- Check for concurrent overwrites of the data file; ensure readers only access immutable, committed files.
- Inspect the wrapped IOException (getCause) for the underlying filesystem/network error and fix that (permissions, connection, disk).
- Re-run the read; transient network/IO errors may succeed on retry after validating the file integrity.
Example fix
// before: reading a file while a writer replaces it
Table table = catalog.loadTable("db.t");
CloseableIterable<Record> rows = SparkUtil.openAllDataFiles(table); // may include files being overwritten
// after: read only committed snapshots and validate file presence
Table table = catalog.loadTable("db.t");
snapshot(table.currentSnapshot().snapshotId()) // pin snapshot so files are immutable
.dataFiles().forEach(f -> Preconditions.check(io.newInputFile(f.location()).exists(), "missing file " + f.location())); Defensive patterns
Strategy: try-catch
Validate before calling
InputFile f = io.newInputFile(location); long actual = f.getLength(); Preconditions.check(actual >= expectedMinSize, "Truncated file %s: %s < %s", location, actual, expectedMinSize);
Try / catch
try {
readColumn(...);
} catch (ParquetDecodingException e) {
if (e.getCause() instanceof IOException) {
verifyFileIntegrity(location); // check length/checksum, re-fetch
retryRead();
} else throw e;
} Prevention
- Only read immutable, committed data files from a pinned snapshot
- Verify file sizes/checksums after download or copy before reading
- Watch for concurrent overwrites of objects in object stores
- Inspect getCause() to distinguish corruption from transient IO errors
When it happens
Trigger: Reading a boolean/int8 column value via readBoolean or readBooleanAsInt when the page's valuesInputStream is exhausted early or the underlying file/byte buffer is unreadable mid-read.
Common situations: Truncated Parquet files from interrupted writes or failed downloads; corrupt page payloads; a FileIO returning a stream over a truncated or partially-updated object (e.g. reading a file while it is being overwritten); filesystem/network I/O errors during reads.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Error reading mini block.
- Failed to read binary data
- could not read page " + valueCount + " in col " + desc
- could not read page %s in col %s
- could not read page in col %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/3b61bcfbbd88d196.
Report an issue: GitHub.