Catalog Labels: client-library read support (Go / Rust / Python / C++)
Summary
Catalog Labels were added to the Iceberg REST spec in #15750 (merged) and implemented on the Java client/engine side as a stacked set of PRs (#18045–#18049). This is a tracking issue to bring the other REST client libraries — iceberg-go, iceberg-rust, iceberg-python (PyIceberg), and iceberg-cpp — to read-path parity.
Labels are catalog-provided enrichment, not table state: they are returned on the load response, are transient/runtime-only, and are never persisted into table metadata or serialized. A client that ignores labels remains spec-compliant.
Wire shape
LoadTableResult / LoadViewResult gain an optional labels object:
"labels": {
"object-labels": { "<key>": "<value>" },
"fields": [ { "field-id": 3, "labels": { "classification": "pii" } } ]
}object-labels: flat catalog-object-level map.fields: per-field labels keyed byfield-id.- A
field-idmay carry multiple keys and may not resolve to a current column (e.g. a dropped column) — clients should tolerate both.
Java reference implementation
- Spec: #15750
- serde: #18045 · table accessor (
SupportsLabels): #18046 · REST server test fixture: #18047 · labels metadata table: #18048 · Spark DESCRIBE: #18049
Shared prerequisite
Client integration tests need a server that emits labels — that is the REST server test fixture (#18047); once merged it must ship in the iceberg-rest-fixture Docker image. This gates the integration-test PRs only; unit-test PRs (mocked responses) can proceed immediately.
- #18047 merged and published to the
iceberg-rest-fixtureimage
Per-repo proposed PRs
Each repo mirrors the Java layering (serde → table accessor → labels metadata table → integration tests), modeled on that client's existing storage-credentials / vended-credentials field. Read-path parity (metadata table) is included in all four. Rust and C++ are table-only (no LoadViewResult yet). Each per-repo group is a stack (each PR based on the previous); repos are independent.
iceberg-python (PyIceberg) — reconcile existing prototype to the spec
- P1 serde + accessor: align internal keys
"table"/"columns"→ spec"object-labels"/"fields", addViewResponse/Viewlabels, unit tests - P2
table.inspect.labels()metadata table - P3 integration tests against the fixture (gated on prerequisite)
iceberg-go
- G1 label types + serde on
loadTableResponse/loadViewResponse+Table/Viewaccessor + unit tests - G2
InspectTable.Labels()metadata table - G3 integration tests against the fixture (gated)
iceberg-cpp — table-only (no views yet)
- C1 serde (
FieldLabels/CatalogLabels+LoadTableResult.labels) +Table::catalog_labels()accessor + first REST serde unit test - C2 labels kind on
inspect::MetadataTable - C3 integration tests against the fixture (gated)
iceberg-rust — table-only (no views yet)
- R1 serde types (in the
icebergcore crate) +labelsonLoadTableResult+public-api.txt - R2
Tablefield + accessor + REST propagation - R3
inspect().labels()metadata table (+ DataFusion adapter) - R4 integration tests against the fixture (gated)
Notes
- Suggested lead order: PyIceberg → Go → C++ → Rust (ascending ceremony).
- Views: Go/Python cover table + view; Rust/C++ are table-only until
LoadViewResultlands in those clients.
Source: apache/iceberg