prestodb/presto · error · OrcCorruptionException

Write validation failed: unexpected string range in %s stati

Error message

Write validation failed: unexpected string range in %s statistics

What it means

For string columns, write validation compares StringStatistics (min/max/sum of lengths) recorded at write time to those read back. The reader is lenient about min/max when the expected value is null (string stats have length truncation limits, and merging row group stats can produce nulls), but sum of lengths must match and any present expected min/max must equal the actual. Mismatch indicates corrupted or altered string data/statistics.

Source

Thrown at presto-orc/src/main/java/com/facebook/presto/orc/OrcWriteValidation.java:576

        StringStatistics expectedStringStatistics = expectedColumnStatistics.getStringStatistics();
        if (expectedStringStatistics != null) {
            expectedStringStatistics = new StringStatistics(
                    minStringTruncateToValidRange(expectedStringStatistics.getMin(), HiveWriterVersion.ORC_HIVE_8732),
                    maxStringTruncateToValidRange(expectedStringStatistics.getMax(), HiveWriterVersion.ORC_HIVE_8732),
                    expectedStringStatistics.isLowerBoundSet(),
                    expectedStringStatistics.isUpperBoundSet(),
                    expectedStringStatistics.getSum());
        }
        StringStatistics actualStringStatistics = actualColumnStatistics.getStringStatistics();
        if (!Objects.equals(actualColumnStatistics.getStringStatistics(), expectedStringStatistics) && expectedStringStatistics != null) {
            // expectedStringStatistics (or the min/max of it) could be null while the actual one might not because
            // expectedStringStatistics is calculated by merging all row group stats in the stripe but the actual one is by scanning each row in the stripe on disk.
            // Merging row group stats can produce nulls given we have string stats limit.
            if (actualStringStatistics == null ||
                    actualStringStatistics.getSum() != expectedStringStatistics.getSum() ||
                    (expectedStringStatistics.getMax() != null && !Objects.equals(actualStringStatistics.getMax(), expectedStringStatistics.getMax())) ||
                    (expectedStringStatistics.getMin() != null && !Objects.equals(actualStringStatistics.getMin(), expectedStringStatistics.getMin()))) {
                throw new OrcCorruptionException(orcDataSourceId, "Write validation failed: unexpected string range in %s statistics", name);
            }
        }
        if (!Objects.equals(actualColumnStatistics.getDateStatistics(), expectedColumnStatistics.getDateStatistics())) {
            throw new OrcCorruptionException(orcDataSourceId, "Write validation failed: unexpected date range in %s statistics", name);
        }
        if (!Objects.equals(actualColumnStatistics.getDecimalStatistics(), expectedColumnStatistics.getDecimalStatistics())) {
            throw new OrcCorruptionException(orcDataSourceId, "Write validation failed: unexpected decimal range in %s statistics", name);
        }
        if (!Objects.equals(actualColumnStatistics.getBloomFilter(), expectedColumnStatistics.getBloomFilter())) {
            throw new OrcCorruptionException(orcDataSourceId, "Write validation failed: unexpected bloom filter in %s statistics", name);
        }
    }

    public static class WriteChecksum
    {
        private final long totalRowCount;
        private final long stripeHash;
        private final List<Long> columnHashes;

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Re-write the file with the Presto ORC writer so string statistics use the same truncation semantics
  2. If the file came from another engine, disable orc.write-validation for those reads
  3. Upgrade Presto to get consistent ORC_HIVE_8732 min/max range handling
  4. Restore the file if storage corruption is confirmed
Defensive patterns

Strategy: try-catch

Try / catch

try {
    orcBatchReader.nextPage();
} catch (OrcCorruptionException e) {
    if (e.getMessage().contains("unexpected string range")) {
        // likely truncation-limit semantics mismatch; re-read with validation off or rewrite file
    }
}

Prevention

When it happens

Trigger: validateColumnStatisticsEquivalent finds actualStringStatistics null while expected is present, sum of string lengths differs, or a non-null expected min/max differs from the actual — at file, stripe, or row group level.

Common situations: Files written by engines with different string statistics truncation limits (HiveWriterVersion ORC_HIVE_8732 handling); corrupted string columns; cross-engine file exchange.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/e87bd9cc0449e2e4. Report an issue: GitHub.