SreeramGarlapati opened a new issue, #2510:
URL: https://github.com/apache/iceberg-rust/issues/2510

   ### Apache Iceberg Rust version
   
   `main` (verified against `a3d2764`).
   
   ### Describe the bug
   
   `update_snapshot_summaries` in `crates/iceberg/src/spec/snapshot_summary.rs` 
panics on the overwrite-truncation path whenever the previous snapshot's 
summary contains a total that doesn't fit `i32`, or any value that isn't a 
decimal integer.
   
   The crash site is line 356:
   
   ```rust
   truncate_table_summary(summary, prev_summary)
       .map_err(|err| {
           Error::new(ErrorKind::Unexpected, "Failed to truncate table 
summary.")
               .with_source(err)
       })
       .unwrap()        // <-- panics on Err
   ```
   
   `truncate_table_summary` calls `get_prop` for every `total-*` property, and 
`get_prop` parses with `parse::<i32>()`. Two failure modes:
   
   1. **Capacity**: `i32::MAX` is ~2.15 billion. Any table whose previous 
snapshot has `total-data-files`, `total-records`, `total-files-size`, etc. 
above that ceiling produces `Err(number too large to fit in target type)`. The 
rest of the file already parses these counters as `u64`, so `get_prop` is the 
odd one out.
   2. **Validation**: any non-numeric value (corruption, manual metadata edits, 
a value written by a foreign implementation) produces `Err(invalid digit found 
in string)`.
   
   Both errors are wrapped into a `Result::Err` and then `.unwrap()`-ed, which 
is a process-level panic — not a recoverable error a caller can handle.
   
   ### Impact
   
   - Any overwrite-with-truncate against a table large enough to cross the 
`i32` ceiling crashes the writer process.
   - Any overwrite against a table whose summary was last touched by another 
implementation crashes the writer process.
   - The crash is on a code path that's reachable by normal API usage 
(`update_snapshot_summaries(.., truncate_full_table=true)` from the overwrite 
transaction), not on an internal-only path.
   
   ### To Reproduce
   
   ```rust
   let big = (i32::MAX as u64 + 1).to_string(); // 2_147_483_648
   
   let previous_summary = Summary {
       operation: Operation::Overwrite,
       additional_properties: HashMap::from([
           (\"total-data-files\".to_string(), big.clone()),
           // ... other totals zero-valued
       ]),
   };
   
   let summary = Summary {
       operation: Operation::Overwrite,
       additional_properties: HashMap::new(),
   };
   
   // Today: panics at snapshot_summary.rs:356:18 with
   //   \"Result::unwrap() on an Err value: ... number too large to fit in 
target type\"
   // Expected: returns Ok with deleted-data-files = \"2147483648\".
   update_snapshot_summaries(summary, Some(&previous_summary), true).unwrap();
   ```
   
   Same shape with `\"not_a_number\"` instead of `big` — same panic, different 
inner error message.
   
   ### Expected behaviour
   
   - Totals up to `u64::MAX` should be accepted (consistent with how 
`update_totals` already treats them).
   - Malformed values should produce a recoverable `Err` (wrapped with the 
existing `\"Failed to truncate table summary.\"` context), not a panic.
   
   ### Willingness to contribute
   
   Yes — fix and red-state-proven tests prepared, PR incoming.


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