{"record":{"id":"1c1e63df42e2f4bc","repo":"apache/iceberg","slug":"failed-to-decode-partition-1c1e63","errorCode":null,"errorMessage":"Failed to decode partition","messagePattern":"Failed to decode partition","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/maintenance/operator/StructLikeSerializer.java","lineNumber":121,"sourceCode":"        boolean isNull = dis.readBoolean();\n        if (isNull) {\n          partition.set(i, null);\n        } else {\n          int length = dis.readInt();\n          byte[] bytes = new byte[length];\n          dis.readFully(bytes);\n          Object value = Conversions.fromByteBuffer(fields.get(i).type(), ByteBuffer.wrap(bytes));\n          // Conversions returns CharBuffer for STRING; PartitionData (and the manifest writer)\n          // expects String.\n          if (value instanceof CharSequence cs && !(value instanceof String)) {\n            value = cs.toString();\n          }\n\n          partition.set(i, value);\n        }\n      }\n    } catch (IOException e) {\n      throw new UncheckedIOException(\"Failed to decode partition\", e);\n    }\n\n    return partition;\n  }\n\n  private void writeField(StructLike struct, int pos, Type fieldType) throws IOException {\n    Object value = struct.get(pos, Object.class);\n    if (value == null) {\n      dos.writeBoolean(true);\n      return;\n    }\n\n    dos.writeBoolean(false);\n    ByteBuffer buf = Conversions.toByteBuffer(fieldType, value);\n    dos.writeInt(buf.remaining());\n    dos.write(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining());\n  }\n}","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/maintenance/operator/StructLikeSerializer.java#L103-L139","documentation":"decodePartition() reads back bytes produced by encodePartition() into a PartitionData. IOExceptions (EOFException, corrupt data, wrong format) are wrapped in UncheckedIOException. It means the byte array does not match the expected layout: a null flag, length, and value per field in the given partitionType order.","triggerScenarios":"Decoding bytes encoded with a different partitionType (field count/type changed); truncated or corrupted byte arrays from state; decoding EMPTY_PARTITION bytes with a non-empty partitionType.","commonSituations":"Partition spec evolution between the job that encoded and the one decoding; state written by a different Iceberg version; deserializing from a state backend after a failed restore.","solutions":["Ensure encode and decode use the same Types.StructType partitionType (from the same table spec version)","Verify the byte[] is not truncated — check the source of the bytes (state, message, event)","Rebuild state/reprocess the affected partition if state was written before a spec change","Add a defensive check that encoded.length > 0 before decodePartition for non-empty partition types"],"exampleFix":"// before: decoding with a changed spec\nStructLike p = StructLikeSerializer.decodePartition(bytes, table.spec().partitionType());\n// after: decode with the spec active when the bytes were written\nStructLike p = StructLikeSerializer.decodePartition(bytes, specAtWriteTime.partitionType());","handlingStrategy":"validation","validationCode":"if (partitionType.fields().isEmpty()) {\n  return; // empty partition: no bytes expected\n}\nif (encoded == null || encoded.length == 0) {\n  throw new IllegalArgumentException(\"No encoded bytes for non-empty partition type \" + partitionType);\n}","typeGuard":null,"tryCatchPattern":"try {\n  StructLike p = StructLikeSerializer.decodePartition(encoded, partitionType);\n} catch (UncheckedIOException e) {\n  LOG.error(\"Corrupt/truncated partition bytes for type {}\", partitionType, e);\n  throw e;\n}","preventionTips":["Encode and decode with the same Types.StructType (same spec snapshot)","Avoid persisting partition bytes across spec changes without re-encoding","Verify state payloads are not truncated when moving between backends"],"tags":["flink","deserialization","partition","eof"],"backgroundTag":"unexpected-response-shape","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}