apache/iceberg · error · UncheckedIOException

Failed to deserialize object

Error message

Failed to deserialize object

What it means

SerializationUtil.deserializeFromBytes wraps Java's native ObjectInputStream deserialization. An IOException during readObject (corrupt/truncated bytes, stream-header mismatch, or a readObject method throwing internally) is rethrown as an UncheckedIOException with this message. It means the byte array is not a valid Java-serialized stream for the expected object.

Solutions

  1. Verify the payload was produced by SerializationUtil.serializeToBytes/serializeToBase64 in the first place
  2. Decode Base64 with Base64.getMimeDecoder() (the matching decoder for getMimeEncoder) and check the bytes start with the Java stream magic 0xAC 0xED
  3. Regenerate the payload from the source object instead of reusing stored bytes
  4. Inspect the chained IOException cause for the real failure (e.g. invalid stream header, class resolution)

Example fix

// before
String decoded = new String(Base64.getDecoder().decode(payload));
T obj = SerializationUtil.deserializeFromBytes(decoded.getBytes());
// after
byte[] bytes = Base64.getMimeDecoder().decode(payload);
T obj = SerializationUtil.deserializeFromBytes(bytes);
Defensive patterns

Strategy: try-catch

Validate before calling

byte[] bytes = Base64.getMimeDecoder().decode(payload);
if (bytes.length < 4 || (bytes[0] & 0xFF) != 0xAC || (bytes[1] & 0xFF) != 0xED) {
  throw new IllegalArgumentException("not a Java-serialized payload");
}

Type guard

boolean isJavaSerialized(byte[] b) {
  return b != null && b.length >= 4 && (b[0] & 0xFF) == 0xAC && (b[1] & 0xFF) == 0xED;
}

Try / catch

try {
  T obj = SerializationUtil.deserializeFromBytes(bytes);
} catch (UncheckedIOException e) {
  log.error("corrupt serialized payload", e);
  obj = regeneratePayload();
}

Prevention

When it happens

Trigger: Calling deserializeFromBytes (directly or via deserializeFromBase64) with bytes that were not produced by serializeToBytes, Base64 strings decoded incorrectly (wrong decoder, e.g. plain Base64 vs MIME), truncated/corrupted payloads stored in configs or event payloads, or serialized data whose embedded objects fail during readObject (e.g. serialVersionUID mismatch is often surfaced through this path).

Common situations: Passing a plain-text or JSON string where a Java-serialized payload is expected; hand-editing or re-encoding Base64 payloads with whitespace/newlines stripped inconsistently with the MIME encoder; upgrading library versions so a stored serialized object no longer round-trips.

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/bb3f5e4b4ef24d2d. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/util/SerializationUtil.java:82

        ObjectOutputStream oos = new ObjectOutputStream(baos)) {
      oos.writeObject(obj);
      return baos.toByteArray();
    } catch (IOException e) {
      throw new UncheckedIOException("Failed to serialize object", e);
    }
  }

  @SuppressWarnings({"DangerousJavaDeserialization", "unchecked"})
  public static <T> T deserializeFromBytes(byte[] bytes) {
    if (bytes == null) {
      return null;
    }

    try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bais)) {
      return (T) ois.readObject();
    } catch (IOException e) {
      throw new UncheckedIOException("Failed to deserialize object", e);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("Could not read object ", e);
    }
  }

  public static String serializeToBase64(Object obj) {
    byte[] bytes = serializeToBytes(obj);
    return new String(Base64.getMimeEncoder().encode(bytes), StandardCharsets.UTF_8);
  }

  public static <T> T deserializeFromBase64(String base64) {
    if (base64 == null) {
      return null;
    }
    byte[] bytes = Base64.getMimeDecoder().decode(base64.getBytes(StandardCharsets.UTF_8));
    return deserializeFromBytes(bytes);
  }
}

View on GitHub (pinned to 86d9c8fc54)