You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by fo...@apache.org on 2026/07/18 20:23:51 UTC
(iceberg-python) branch main updated: fix: raise `ValidationError` for decimal precision outside range (#3585)
This is an automated email from the ASF dual-hosted git repository.
Fokko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git
The following commit(s) were added to refs/heads/main by this push:
new c2093328c fix: raise `ValidationError` for decimal precision outside range (#3585)
c2093328c is described below
commit c2093328cf9fdf0d7d1da485e9f3b0681cc2ed05
Author: Platon G. Gimp <pl...@gmail.com>
AuthorDate: Sun Jul 19 01:23:46 2026 +0500
fix: raise `ValidationError` for decimal precision outside range (#3585)
Closes #3583
# Rationale for this change
According to the Iceberg specification, decimal precision must be
between 1 and 38. Previously, `pyiceberg` silently accepted invalid
values (such as `precision=39` or `0`), which could lead to data
corruption or crashes downstream when encoding/decoding fixed-byte
decimals (matching the Java implementation's
`IllegalArgumentException`).
This PR adds a defensive validation guard into `DecimalType.__init__` to
raise a `ValidationError` when the precision is out of bounds `[1, 38]`.
Additionally, fixed an existing invalid type definition
(`DecimalType(100, 2)`) inside `tests/test_schema.py` which was
violating the specification bounds and causing the new validation guard
to trip during the integration test suite.
## Are these changes tested?
Yes, added dedicated unit tests in `tests/test_types.py`:
- `test_decimal_precision_validation` covers upper bounds
(`precision=39`), lower bounds (`precision=0`, `precision=-5`), and
ensures valid boundary values (`precision=38`) work perfectly.
Also updated existing test assertions in `tests/test_schema.py` to use a
compliant precision value (`38`).
## Are there any user-facing changes?
Yes, creating a `DecimalType` with an invalid precision will now
explicitly raise a `pyiceberg.exceptions.ValidationError` instead of
failing silently at runtime.
---
pyiceberg/types.py | 8 ++++++++
tests/test_schema.py | 2 +-
tests/test_types.py | 15 +++++++++++++++
3 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/pyiceberg/types.py b/pyiceberg/types.py
index 3c9821536..fd1d8fc0a 100644
--- a/pyiceberg/types.py
+++ b/pyiceberg/types.py
@@ -326,6 +326,14 @@ class DecimalType(PrimitiveType):
def __init__(self, precision: int, scale: int) -> None:
super().__init__(root=(precision, scale))
+ @model_validator(mode="after")
+ def check_precision(self) -> DecimalType:
+ precision = getattr(self, "precision", None) or self.root[0]
+
+ if not (1 <= precision <= 38):
+ raise ValidationError(f"Decimal precision must be between 1 and 38 (inclusive), got: {precision}")
+ return self
+
@model_serializer
def ser_model(self) -> str:
"""Serialize the model to a string."""
diff --git a/tests/test_schema.py b/tests/test_schema.py
index 93ddc1620..aacdbc7d5 100644
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -67,7 +67,7 @@ TEST_PRIMITIVE_TYPES = [
FloatType(),
DoubleType(),
DecimalType(10, 2),
- DecimalType(100, 2),
+ DecimalType(38, 2),
StringType(),
DateType(),
TimeType(),
diff --git a/tests/test_types.py b/tests/test_types.py
index 5e95687ba..375fb9cdb 100644
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -920,3 +920,18 @@ def test_nested_field_geography_with_params_as_string() -> None:
assert isinstance(field.field_type, GeographyType)
assert field.field_type.crs == "EPSG:4326"
assert field.field_type.algorithm == "planar"
+
+
+def test_decimal_precision_validation() -> None:
+ """Test that DecimalType rejects precision outside the [1, 38] range."""
+ decimal_type = DecimalType(38, 2)
+ assert decimal_type.precision == 38
+
+ with pytest.raises(ValidationError, match="Decimal precision must be between 1 and 38"):
+ DecimalType(39, 2)
+
+ with pytest.raises(ValidationError, match="Decimal precision must be between 1 and 38"):
+ DecimalType(0, 2)
+
+ with pytest.raises(ValidationError, match="Decimal precision must be between 1 and 38"):
+ DecimalType(-5, 2)