[Bug] Shredded Variant files miss internal field IDs and cannot be read by Java Paimon
@SteNicholas is already working on this.
Since Sep 15, 2026.
Assessment
This issue has not been assessed yet.
Description
Search before asking
- I searched in the issues and found nothing similar.
Paimon-cpp version
- Apache Paimon C++ v0.3.0 (
efbfc848) - The problem is also present on current
main(21228d92b30cc7e987239f0dbca4371120bdfb0b). - Reader used to reproduce the failure: Apache Paimon Java 1.4.2.
Minimal reproduce step
-
Create a Paimon table containing a
VARIANTcolumn. -
Write at least one data file with paimon-cpp and enable Variant shredding, either with a configured shredding schema or with schema inference. A minimal typed projection such as the following is sufficient:
payload VARIANT typed_value ROW<age INT, city STRING> -
Inspect the Parquet schema written by paimon-cpp. The outer Paimon table field has a field ID, but the generated Variant physical fields (
metadata,value,typed_value) and descendants oftyped_valuedo not have Parquet field IDs. -
Read the file through Apache Paimon Java 1.4.2, for example from Spark.
The Java reader fails while constructing the Variant read plan, before reading any row:
java.lang.NullPointerException: Cannot invoke
"org.apache.parquet.schema.Type$ID.intValue()" because the return value of
"org.apache.parquet.schema.Type.getId()" is null
at org.apache.paimon.format.parquet.ParquetSchemaConverter.convertToPaimonField(ParquetSchemaConverter.java:386)
at org.apache.paimon.format.parquet.ParquetSchemaConverter.convertToPaimonField(ParquetSchemaConverter.java:406)
at org.apache.paimon.format.parquet.VariantUtils.variantFileType(VariantUtils.java:49)
The existing VariantParquetTest.ShreddedWriteAndReadRoundTrip can also expose the problem by opening the raw Parquet footer and asserting that every generated field in the shredded Variant subtree has a field ID. The current C++-write/C++-read round trip succeeds because it does not verify Java interoperability or these footer IDs.
What doesn't meet your expectations?
Expected behavior
A shredded Variant file written by paimon-cpp should be readable by the corresponding Java Paimon implementation. Its generated physical schema should carry deterministic Paimon/Parquet field IDs compatible with the schema produced by the Java writer.
Actual behavior
paimon-cpp can write and read the file itself, but Java Paimon cannot open it. ParquetSchemaConverter recursively converts the typed_value subtree and requires every converted Parquet field to have an ID. It dereferences a null Type.getId() for the first generated field without one.
The source of the mismatch appears to be:
VariantShreddingSchemaImplcreatesmetadata,value,typed_value, nested object fields, and list elements with plainarrow::field(...), withoutpaimon.idmetadata.VariantShreddingWritePlaninstalls this generated physical type while preserving only the outer table field metadata.ParquetFieldIdConvertercopies an existingpaimon.idtoPARQUET:field_id; it does not assign IDs when the generated Arrow field has none.
Configured shredding, inferred per-file shredding, and adaptive shredding all use this physical-schema construction path, so all modes can produce files that Java Paimon cannot read when typed_value is present.
This blocks cross-language interoperability. For example, an engine using paimon-cpp for native writes currently has to fall back to the Java writer for shredded Variant data, otherwise Java/Spark readers cannot consume the resulting files.
Anything else?
The ordinary unshredded Variant layout does not have this problem: UnshreddedStructType explicitly assigns IDs 0 and 1 to value and metadata.
Although Parquet field IDs are optional in the file-format specification and Variant physical members are identified by name, the current Java Paimon reader uses its generic Parquet-to-Paimon schema converter for typed_value, and that converter requires IDs. Therefore the file is not interoperable with the Java implementation that paimon-cpp targets.
Suggested fix and regression coverage:
- Assign deterministic
paimon.idmetadata to all generated shredded Variant fields, including nested object fields and list/map descendants, matching Java Paimon's physical schema conventions. - Ensure the IDs survive configured, inferred, and adaptive shredding paths and are emitted as Parquet field IDs.
- Extend the C++ Parquet test to assert the raw footer IDs for a nested shredded schema.
- Add a cross-language regression test that writes a shredded Variant file with paimon-cpp and reads it with Java Paimon (and ideally the reverse direction).
Are you willing to submit a PR?
- I'm willing to submit a PR!
- Dominant language
- C++
- Stars
- 65
- Forks
- 29
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 78
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from apache/paimon-cpp
-
enhancement
apache/paimon-cpp#381 · 1 assignee ·
-
Difficulty 4/5 3-5 days Newbie friendliness 30/100
apache/paimon-cpp#375 · 1 assignee ·
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 45/100
apache/paimon-cpp#361 · 1 assignee ·
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 45/100
apache/paimon-cpp#325 · 1 assignee ·
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 35/100
apache/paimon-cpp#319 · 1 reaction · 1 assignee ·
All issues in apache/paimon-cpp
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
objectionary/eo-graphs#74 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 95/100
-
enhancement
Difficulty 1/5 Under an hour Newbie friendliness 88/100
QuantStack/git2cpp#187 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100