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.
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)
Solutions
- Use the same Iceberg version (or a compatible one) that wrote the savepoint when restoring.
- If upgrade is required, let the old job finish or drain rather than restoring old split state into a new Iceberg version.
- Verify the shaded jar contains all org.apache.iceberg.flink split classes (no class relocation mismatch).
- 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
- Keep the Iceberg version stable between stop-with-savepoint and restore
- Include all iceberg-flink classes in the job jar (verify shading/relocation)
- Test savepoint/restore across your upgrade matrix before production upgrades
- Avoid mixing Iceberg versions on the same Flink cluster classpath
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
- Could not deserialize the WriteResult object
- Unrecognized version or corrupt state: <version>
- Unknown serialize version: ${version}
- Unrecognized version or corrupt state: ${version}
- Could not deserialize the WriteResult object
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9d001dd78f71ba76.
Report an issue: GitHub.