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

  1. Verify the Parquet file is complete and not truncated (check file size vs manifest/expected length); re-copy or re-download the file.
  2. Check for concurrent overwrites of the data file; ensure readers only access immutable, committed files.
  3. Inspect the wrapped IOException (getCause) for the underlying filesystem/network error and fix that (permissions, connection, disk).
  4. 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

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/3b61bcfbbd88d196. Report an issue: GitHub.