123digits opened a new issue, #2365:
URL: https://github.com/apache/iceberg-rust/issues/2365

   ### Apache Iceberg Rust version
   
   None
   
   ### Describe the bug
   
   # Manifest partition-spec serialization/deserialization is not interoperable 
with iceberg-java / iceberg-cpp / pyiceberg
   
   ## Problem
   
   `ManifestWriter` in iceberg-rust writes the `partition-spec` entry of the 
Avro manifest user metadata as a bare JSON array of fields, and 
`ManifestMetadata::try_from_avro_bytes` only accepts that same bare-array 
shape. Every other Iceberg implementation (`iceberg-java`, `iceberg-cpp`, 
`pyiceberg`) writes (and requires) the spec-compliant serialized 
`PartitionSpec` object: `{"spec-id": N, "fields": [...]}`.
   
   Consequences:
   
   - **iceberg-rust fails on commit** when the table has any snapshot committed 
by a non-rust writer. During `fast_append`, iceberg-rust loads the parent 
snapshot's manifests for the duplicate-file check (`transaction/snapshot.rs`), 
and deserialization blows up with:
     ```
     DataInvalid => Fail to parse partition spec in manifest metadata,
     source: invalid type: map, expected a sequence at line 1 column 0
     ```
   - **Other Iceberg engines fail to read iceberg-rust manifests**, because 
they expect the `{"spec-id":N,"fields":[...]}` object.
   
   Net result: iceberg-rust can't share a table with any other implementation 
in either direction.
   
   ## Reproduce
   
   1. Partition a table with any partition spec (using iceberg-java, 
iceberg-cpp, or pyiceberg).
   2. Commit at least one snapshot via that non-rust writer.
   3. Attempt a `fast_append` commit from iceberg-rust on the same table.
   
   Error surfaces from `crates/iceberg/src/spec/manifest/metadata.rs:83` via 
`serde_json::from_slice::<Vec<PartitionField>>(bs)`.
   
   Observed on `0.8.0`, `0.9.0`, and `main` (commit `4b0b3525`) as of 
2026-04-24.
   
   ## Expected behavior
   
   iceberg-rust should:
   1. Write `partition-spec` as the spec-compliant object form so other 
implementations can read our manifests.
   2. Accept both shapes on read — the spec-compliant object AND the historical 
bare-array form — so existing rust-written manifests continue to deserialize.
   
   ## Proposed fix
   
   Two small changes in `crates/iceberg/src/spec/manifest/`:
   
   **`writer.rs`** — serialize the full `PartitionSpec`:
   ```rust
   to_vec(&self.metadata.partition_spec).map_err(...)  // was: 
to_vec(&...partition_spec.fields())
   ```
   
   **`metadata.rs`** — accept either shape on read, preferring the bare-array 
path for backwards compatibility:
   ```rust
   serde_json::from_slice::<Vec<PartitionField>>(bs)
       .or_else(|_| {
           #[derive(serde::Deserialize)]
           struct PartitionSpecJson { fields: Vec<PartitionField> }
           serde_json::from_slice::<PartitionSpecJson>(bs).map(|s| s.fields)
       })
       .map_err(...)
   ```
   
   Existing 17 manifest unit tests (including 
`writer::tests::test_add_delete_existing` and 
`test_v3_delete_manifest_delete_file_roundtrip`) pass unchanged with both 
patches applied. Diff total: 29 insertions, 8 deletions across the two files.
   
   I have a local patch working against a table with mixed rust/cpp writers. 
Working on putting up a PR for this shortly.
   
   ### To Reproduce
   
   _No response_
   
   ### Expected behavior
   
   _No response_
   
   ### Willingness to contribute
   
   I can contribute a fix for this bug independently


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to