{"record":{"id":"b6a82dcca7395a5c","repo":"apache/beam","slug":"cannot-serialize-deletefile-its-partition-spec-id-does-not","errorCode":null,"errorMessage":"Cannot serialize DeleteFile: its partition spec id {} does not match the provided spec id {}.","messagePattern":"Cannot serialize DeleteFile: its partition spec id (.+?) does not match the provided spec id (.+?)\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/SerializableDeleteFile.java","lineNumber":210,"sourceCode":"      DeleteFile deleteFile, Map<Integer, PartitionSpec> specs, boolean includeMetrics) {\n    return from(\n        deleteFile,\n        checkStateNotNull(\n            specs.get(deleteFile.specId()),\n            \"Could not create a SerializableDeleteFile because DeleteFile is written using a partition spec id '%s' that is not found in the provided specs: %s\",\n            deleteFile.specId(),\n            specs.keySet()),\n        includeMetrics);\n  }\n\n  public static SerializableDeleteFile from(DeleteFile deleteFile, PartitionSpec spec) {\n    return from(deleteFile, spec, true);\n  }\n\n  public static SerializableDeleteFile from(\n      DeleteFile deleteFile, PartitionSpec spec, boolean includeMetrics) {\n    if (spec.specId() != deleteFile.specId()) {\n      throw new IllegalArgumentException(\n          String.format(\n              \"Cannot serialize DeleteFile: its partition spec id %s does not match the provided \"\n                  + \"spec id %s.\",\n              deleteFile.specId(), spec.specId()));\n    }\n    // jsonPartition is the primary (handles evolved specs, special characters).\n    // partitionPath is the fallback for values that don't round-trip through JSON.\n    String jsonPartition = SingleValueParser.toJson(spec.partitionType(), deleteFile.partition());\n    String partitionPath = spec.partitionToPath(deleteFile.partition());\n\n    SerializableDeleteFile.Builder builder =\n        SerializableDeleteFile.builder()\n            .setLocation(deleteFile.location())\n            .setFileFormat(deleteFile.format().name())\n            .setFileSizeInBytes(deleteFile.fileSizeInBytes())\n            .setPartitionPath(partitionPath)\n            .setJsonPartition(jsonPartition)\n            .setPartitionSpecId(deleteFile.specId())","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/SerializableDeleteFile.java#L192-L228","documentation":"SerializableDeleteFile.from() mirrors SerializableDataFile: it requires the provided PartitionSpec's id to equal the DeleteFile's specId and throws IllegalArgumentException otherwise. Delete files (equality or position deletes) carry the spec id they were written under; serializing with a mismatched spec would misplace the delete in partition space.","triggerScenarios":"Calling SerializableDeleteFile.from(deleteFile, spec, includeMetrics) with a spec whose specId differs from deleteFile.specId(), commonly using table.spec() for delete files created under an earlier, evolved partition spec.","commonSituations":"Tables that evolved their partition spec while having delete files from the old spec; pairing all delete files with the table's current spec during a compaction/cleanup job; deserializing plan results from a checkpointed older table version.","solutions":["Resolve the spec via the table's spec map: table.specs().get(deleteFile.specId()).","When listing delete files via scans, carry the spec associated with the scan task rather than table.spec().","Refresh the table/collection point so stale spec ids are re-resolved after evolution."],"exampleFix":"// before\nSerializableDeleteFile.from(deleteFile, table.spec(), true);\n// after\nSerializableDeleteFile.from(deleteFile, table.specs().get(deleteFile.specId()), true);","handlingStrategy":"validation","validationCode":"if (spec.specId() != deleteFile.specId()) {\n  spec = table.specs().get(deleteFile.specId());\n  if (spec == null) throw new IllegalStateException(\"No spec found for delete file specId \" + deleteFile.specId());\n}","typeGuard":null,"tryCatchPattern":"try {\n  SerializableDeleteFile s = SerializableDeleteFile.from(deleteFile, spec, true);\n} catch (IllegalArgumentException e) {\n  // re-resolve spec by deleteFile.specId() and retry\n}","preventionTips":["Resolve specs per delete file via table.specs().get(deleteFile.specId()).","Refresh table snapshots before serializing delete files in maintenance jobs.","Test round-trips on tables that evolved their partition spec."],"tags":["iceberg","java","serialization","delete-file","partition-spec"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}