apache/iceberg · warning · RuntimeException

Fail to deserialize aggregated statistics,change to v1

Error message

Fail to deserialize aggregated statistics,change to v1

What it means

RuntimeException thrown inside StatisticsUtil.deserializeCompletedStatistics when the deserialized CompletedStatistics fails its isValid() check, indicating the current (latest) SortKeySerializer could not correctly parse the checkpoint data. The method then catches it and retries the whole deserialization with sort key serializer version 1, because restoring from a lower version requires the v1 format; if that retry also fails an UncheckedIOException is thrown.

Source

Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/sink/shuffle/StatisticsUtil.java:81

  static byte[] serializeCompletedStatistics(
      CompletedStatistics completedStatistics,
      TypeSerializer<CompletedStatistics> statisticsSerializer) {
    try {
      DataOutputSerializer out = new DataOutputSerializer(1024);
      statisticsSerializer.serialize(completedStatistics, out);
      return out.getCopyOfBuffer();
    } catch (IOException e) {
      throw new UncheckedIOException("Fail to serialize aggregated statistics", e);
    }
  }

  static CompletedStatistics deserializeCompletedStatistics(
      byte[] bytes, CompletedStatisticsSerializer statisticsSerializer) {
    try {
      DataInputDeserializer input = new DataInputDeserializer(bytes);
      CompletedStatistics completedStatistics = statisticsSerializer.deserialize(input);
      if (!completedStatistics.isValid()) {
        throw new RuntimeException("Fail to deserialize aggregated statistics,change to v1");
      }

      return completedStatistics;
    } catch (Exception e) {
      try {
        // If we restore from a lower version, the new version of SortKeySerializer cannot correctly
        // parse the checkpointData, so we need to first switch the version to v1. Once the state
        // data is successfully parsed, we need to switch the serialization version to the latest
        // version to parse the subsequent data passed from the TM.
        statisticsSerializer.changeSortKeySerializerVersion(1);
        DataInputDeserializer input = new DataInputDeserializer(bytes);
        CompletedStatistics deserialize = statisticsSerializer.deserialize(input);
        statisticsSerializer.changeSortKeySerializerVersionLatest();
        return deserialize;
      } catch (IOException ioException) {
        throw new UncheckedIOException("Fail to deserialize aggregated statistics", ioException);
      }
    }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. No direct fix needed: the method automatically retries with sort key serializer v1 and switches back to latest afterward
  2. If the v1 fallback also fails (UncheckedIOException), the checkpoint bytes are incompatible — recreate the job without restoring from the old savepoint
  3. Ensure the CompletedStatisticsSerializer version handling is active and changeSortKeySerializerVersionLatest is invoked after the v1 parse
  4. Check the wrapped exception cause to see whether corruption, not versioning, is the root problem

Example fix

// before
CompletedStatistics stats = StatisticsUtil.deserializeCompletedStatistics(bytes, serializer);
// after (library already falls back internally; guard caller side)
try {
  CompletedStatistics stats = StatisticsUtil.deserializeCompletedStatistics(bytes, serializer);
} catch (UncheckedIOException e) {
  // incompatible old checkpoint; start fresh or re-checkpoint with matching version
  throw new IllegalStateException("Aggregated statistics checkpoint incompatible across versions", e);
}
Defensive patterns

Strategy: fallback

Validate before calling

// Verify checkpoint was produced with a compatible Iceberg version before restoring
boolean compatible = checkpointIcebergVersion.equals(currentIcebergVersion);

Type guard

boolean isRestorable(byte[] bytes, CompletedStatisticsSerializer ser) { try { ser.deserialize(new DataInputDeserializer(bytes)); return true; } catch (Exception e) { return false; } }

Try / catch

try { CompletedStatistics s = StatisticsUtil.deserializeCompletedStatistics(bytes, serializer); } catch (UncheckedIOException e) { /* v1 fallback failed; recreate state without restore */ }

Prevention

When it happens

Trigger: Restoring a Flink job from a checkpoint/savepoint written by an older Iceberg version while the current job uses the latest SortKeySerializer: the bytes parse but produce an invalid CompletedStatistics, triggering this message and the v1 fallback.

Common situations: Upgrading Iceberg across Flink restores; checkpoints produced with old sort-key serialization mixed with a new version serializer; state migrated between clusters with different Iceberg builds.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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