apache/iceberg · error · RuntimeException

Failed to deserialize the split.

Error message

Failed to deserialize the split.

What it means

deserializeV1 deserializes a version-1 serialized IcebergSourceSplit using Flink's InstantiationUtil Java serialization. If the bytes reference a class not present on the classpath, ClassNotFoundException is wrapped in this RuntimeException. It indicates the split state bytes cannot be reconstructed in the current runtime.

Solutions

  1. Use the same Iceberg version (or a compatible one) that wrote the savepoint when restoring.
  2. If upgrade is required, let the old job finish or drain rather than restoring old split state into a new Iceberg version.
  3. Verify the shaded jar contains all org.apache.iceberg.flink split classes (no class relocation mismatch).
  4. Check Flink classloader settings (classloader.check-leaked-classloader, parent-first/child-first) if ClassNotFoundException appears only at runtime.
Defensive patterns

Strategy: try-catch

Try / catch

try { split = IcebergSourceSplit.deserializeV1(bytes); } catch (RuntimeException e) { if (e.getCause() instanceof ClassNotFoundException) { throw new IllegalStateException('Savepoint written with a different Iceberg version; restore with matching version', e); } throw e; }

Prevention

When it happens

Trigger: Restoring a Flink savepoint/checkpoint whose operator state contains serialized splits referencing classes (e.g. old split or table classes) not found by the current classloader - typically after upgrading Iceberg or relocating/renaming classes.

Common situations: Upgrading the Iceberg version between a job stop-with-savepoint and resume; fat-jar shading issues where serializer classes are excluded; classloader isolation in Flink per-job/user-code classloaders.

Related errors


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

Appendix: source

Thrown at flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/source/split/IcebergSourceSplit.java:131

                        .add("length", fileScanTask.length())
                        .toString())
            .collect(Collectors.toList()));
  }

  byte[] serializeV1() throws IOException {
    if (serializedBytesCache == null) {
      serializedBytesCache = InstantiationUtil.serializeObject(this);
    }

    return serializedBytesCache;
  }

  static IcebergSourceSplit deserializeV1(byte[] serialized) throws IOException {
    try {
      return InstantiationUtil.deserializeObject(
          serialized, IcebergSourceSplit.class.getClassLoader());
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("Failed to deserialize the split.", e);
    }
  }

  byte[] serializeV2() throws IOException {
    return serialize(2);
  }

  byte[] serializeV3() throws IOException {
    return serialize(3);
  }

  private byte[] serialize(int version) throws IOException {
    if (serializedBytesCache == null) {
      DataOutputSerializer out = SERIALIZER_CACHE.get();
      Collection<FileScanTask> fileScanTasks = task.tasks();
      Preconditions.checkArgument(
          fileOffset >= 0 && fileOffset < fileScanTasks.size(),
          "Invalid file offset: %s. Should be within the range of [0, %s)",

View on GitHub (pinned to 86d9c8fc54)