mfellner commented on issue #2418:
URL: https://github.com/apache/iceberg-rust/issues/2418#issuecomment-6112672992

   Related to #2411 (v3 tracking).
   
   Re-checked against main at a76678363.
   
   **Current schema: covered on main.** Creating a v2 table, or loading v2 
metadata whose current schema contains `timestamp_ns`, `timestamptz_ns`, 
`variant` or `unknown`, now fails with:
   
   ```
   DataInvalid => Invalid schema for v2:
   - Invalid type for x: timestamp_ns is not supported until v3 but format 
version is v2.
   ```
   
   The type floors and this check were added in #2188 (merged 2026-07-16). 
According to the git tags, #2188 is in v0.11.0-rc.1 and later, and not in 
v0.10.1. `unknown` was added later in #2773, which is not in any tag up to 
v0.11.0-rc.2. #2417, which referenced this issue, was closed without merging 
with the comment "Covered by #2188".
   
   **Remaining gap: non-current schemas.** The check runs only on the current 
schema. `TableMetadata::try_normalize` calls 
`validate_schema_format_compatibility`, which checks `current_schema()` only. 
As a result, on a v2 table:
   
   - `TableMetadataBuilder::add_schema(..)` followed by `build()` returns `Ok` 
when a non-current schema contains `timestamp_ns`, `timestamptz_ns`, `variant` 
or `unknown`.
   - Deserializing v2 metadata JSON that contains such a historical schema 
succeeds.
   
   Java rejects the first case. `TableMetadata.Builder.addSchemaInternal` calls 
`Schema.checkCompatibility(schema, formatVersion)`, which throws 
`IllegalStateException`. This comes from reading apache/iceberg main, not from 
running Java. Java's metadata parser does not run this check on the schemas it 
reads, so the difference is limited to the builder path.
   
   Expected: `add_schema` rejects a schema that uses types the table's format 
version does not support, as Java does. Whether loading should also reject 
historical schemas is for maintainers to decide, since Java's parser accepts 
them.
   
   Maintainers could close this issue and track the non-current-schema gap 
separately, or retitle this one to cover it.
   
   <details>
   <summary>Repro (scratch copy of a76678363, integration test using only the 
public API)</summary>
   
   ```rust
   use iceberg::spec::{NestedField, PrimitiveType, Schema, TableMetadata, 
TableMetadataBuilder, Type};
   
   const V2_METADATA: &str = 
include_str!("../testdata/table_metadata/TableMetadataV2Valid.json");
   
   #[test]
   fn builder_add_schema_with_timestamp_ns() {
       let base: TableMetadata = serde_json::from_str(V2_METADATA).unwrap();
       let schema = Schema::builder()
           .with_schema_id(2)
           .with_fields(vec![
               NestedField::optional(2, "ts", 
Type::Primitive(PrimitiveType::TimestampNs)).into(),
           ])
           .build()
           .unwrap();
       let res = TableMetadataBuilder::new_from_metadata(base, None)
           .add_schema(schema)
           .and_then(|b| b.build());
       println!("BUILDER ok={} err={:?}", res.is_ok(), 
res.as_ref().err().map(|e| e.to_string()));
   }
   
   #[test]
   fn deserialize_v2_metadata_with_historical_timestamp_ns_schema() {
       let mut v: serde_json::Value = 
serde_json::from_str(V2_METADATA).unwrap();
       v["schemas"].as_array_mut().unwrap().push(serde_json::json!({
           "type": "struct",
           "schema-id": 2,
           "fields": [{"id": 2, "name": "ts", "required": false, "type": 
"timestamp_ns"}]
       }));
       let res = serde_json::from_value::<TableMetadata>(v);
       println!("DESER ok={} err={:?}", res.is_ok(), res.as_ref().err().map(|e| 
e.to_string()));
   }
   ```
   
   Output on main (`cargo test --offline -p iceberg --test repro_2418_min -- 
--nocapture`):
   
   ```
   BUILDER ok=true err=None
   DESER ok=true err=None
   ```
   
   The same two tests with `timestamptz_ns`, `variant` and `unknown` in place 
of `timestamp_ns` also return `ok=true`.
   </details>
   
   Found during an agent-assisted audit of v3 support (see #2411). The 
reproduction above was run against main at a76678363.


-- 
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