apache / apache/iceberg-rust

fix: Manifest partition-spec serialization/deserialization is not interoperable with iceberg-java / iceberg-cpp / pyiceberg

Open
#2,365 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
1.4k
Forks
567
Avg merge
2d 2h
Merged PRs (30d)
93

Description

### 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::>(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::>(bs)
.or_else(|_| {
#[derive(serde::Deserialize)]
struct PartitionSpecJson { fields: Vec }
serde_json::from_slice::(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

Contributor guide

Open the contributing guide

Research direction

Start with crates/iceberg/src/spec/manifest/writer.rs and metadata.rs, especially the serialization call at metadata.rs:83 and the existing manifest unit tests. Run the 17 manifest tests, including writer::tests::test_add_delete_existing and test_v3_delete_manifest_delete_file_roundtrip. Done means manifests use the interoperable PartitionSpec shape and both that form and the historical bare-array form deserialize successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
data-engineering
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.