From 8678d40115547486481a30bb6cd788af5ae7d8e6 Mon Sep 17 00:00:00 2001 From: subotac <73706465+subotac@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:10:23 +0300 Subject: [PATCH] fix(arrow-json): validate map value nullability --- arrow-json/src/reader/map_array.rs | 15 ++++++--------- arrow-json/src/reader/mod.rs | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/arrow-json/src/reader/map_array.rs b/arrow-json/src/reader/map_array.rs index 396b60b1624e..abb035193c39 100644 --- a/arrow-json/src/reader/map_array.rs +++ b/arrow-json/src/reader/map_array.rs @@ -130,15 +130,12 @@ impl ArrayDecoder for MapArrayDecoder { let key_array = self.keys.decode(tape, &key_pos)?; let value_array = self.values.decode(tape, &value_pos)?; - // SAFETY: fields/arrays match the schema, lengths are equal, no nulls - let entries = unsafe { - StructArray::new_unchecked_with_length( - self.key_value_fields.clone(), - vec![key_array, value_array], - None, - key_pos.len(), - ) - }; + let entries = StructArray::try_new_with_length( + self.key_value_fields.clone(), + vec![key_array, value_array], + None, + key_pos.len(), + )?; let nulls = nulls.as_mut().and_then(|x| x.finish()); // SAFETY: offsets are built monotonically starting from 0 diff --git a/arrow-json/src/reader/mod.rs b/arrow-json/src/reader/mod.rs index ea4cbe2664f6..bc95f9562b6f 100644 --- a/arrow-json/src/reader/mod.rs +++ b/arrow-json/src/reader/mod.rs @@ -1325,6 +1325,31 @@ mod tests { assert_eq!(formatter.value(2).to_string(), "{c: null, a: [baz]}"); } + #[test] + fn test_map_non_nullable_value() { + let map = Field::new_map( + "map", + Field::MAP_ENTRIES_FIELD_DEFAULT_NAME, + Field::new(Field::MAP_KEY_FIELD_DEFAULT_NAME, DataType::Utf8, false), + Field::new(Field::MAP_VALUE_FIELD_DEFAULT_NAME, DataType::Utf8, false), + false, + false, + ); + let schema = Arc::new(Schema::new(vec![map])); + let buf = r#"{"map": {"key": null}}"#; + + let err = ReaderBuilder::new(schema) + .build(Cursor::new(buf.as_bytes())) + .unwrap() + .read() + .unwrap_err(); + + assert_eq!( + err.to_string(), + "Invalid argument error: Found unmasked nulls for non-nullable StructArray field \"value\"" + ); + } + #[test] fn test_not_coercing_primitive_into_string_without_flag() { let schema = Arc::new(Schema::new(vec![Field::new("a", DataType::Utf8, true)]));