apache/beam · error · IllegalArgumentException
value is out of range for Decimal(, )
Error message
value is out of range for Decimal(, )
What it means
Thrown by ClickHouseWriter.truncateAndCheckDecimal when a BigDecimal, after truncation to the column scale, still exceeds the maximum magnitude of a ClickHouse Decimal of the given precision (unscaled abs value >= 10^precision). The writer rejects values that would not fit rather than silently corrupting data.
Solutions
- Pre-truncate or rescale the value before writing so it fits the declared precision/scale.
- Alter the ClickHouse column to a wider type (Decimal64/Decimal128) if larger values are legitimate.
- Validate upstream data ranges against the target precision before the write.
- Align the Beam schema's Decimal precision/scale with the ClickHouse table definition.
Example fix
// before
writer.decimalValue(new BigDecimal("100000")); // Decimal(5,0) max is 99999
// after
BigDecimal v = new BigDecimal("100000").setScale(0, RoundingMode.DOWN);
if (v.abs().compareTo(new BigDecimal("99999")) > 0) { throw new ValidationException("too large"); }
writer.decimalValue(v); Defensive patterns
Strategy: validation
Validate before calling
import java.math.*;
boolean fitsClickHouseDecimal(BigDecimal value, int precision, int scale) {
BigDecimal truncated = value.setScale(scale, RoundingMode.DOWN);
BigDecimal max = BigDecimal.TEN.pow(precision).subtract(BigDecimal.ONE);
return truncated.abs().compareTo(max) <= 0;
} Type guard
boolean isBigDecimal(Object v) { return v instanceof java.math.BigDecimal; } Try / catch
try {
writer.decimalValue(bigDecimalValue);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("out of range for Decimal")) {
throw new DataException("Value exceeds ClickHouse Decimal column capacity: " + e.getMessage());
}
throw e;
} Prevention
- Keep Beam Row Decimal schema precision/scale identical to the ClickHouse table DDL.
- Range-check aggregated values (SUM/MUL) against column bounds before writing.
- Prefer wider types (Decimal(76, s) or Float64) for computed columns.
- Truncate with the same RoundingMode.DOWN semantics the writer uses, in preprocessing.
When it happens
Trigger: Calling writeValue/decimalValue with a BigDecimal whose integer part has more digits than the target Decimal precision allows — e.g. 100000 into Decimal(5,0) (max 99999), or 123.456 into Decimal(4,2).
Common situations: Aggregations (SUM, multiplication) producing values larger than the declared column precision; mismatch between the Beam Row schema and the actual ClickHouse table; ingesting source data whose scale/precision assumptions changed.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- DateTime64 requires a Joda ReadableInstant or…
- Decimal precision must be in [1, 76], got
- Decimal scale must be in [0, ], got
- Does not support converting DECIMAL type value
- Failed to get table schema for table:
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/5a8e2b275f8647b1.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/clickhouse/src/main/java/org/apache/beam/sdk/io/clickhouse/ClickHouseWriter.java:75
}
}
/**
* Truncates a value to a {@code Decimal(precision, scale)} column's scale and checks it against
* the column's declared range.
*
* <p>Excess fractional digits are discarded toward zero, matching ClickHouse's own behavior and
* the truncation {@link BinaryStreamUtils#writeDecimal} would otherwise apply. The result is then
* bounded by the declared precision: {@code writeDecimal} only range-checks against the backing
* storage width (32/64/128/256 bits, selected from the precision), which is wider than the
* declared type, and ClickHouse's RowBinary reader does not re-check. Without this, a value such
* as {@code 100000} would be stored in a {@code Decimal(5, 0)} column whose declared maximum is
* {@code 99999}.
*/
static BigDecimal truncateAndCheckDecimal(BigDecimal value, int precision, int scale) {
BigDecimal truncated = value.setScale(scale, RoundingMode.DOWN);
if (truncated.unscaledValue().abs().compareTo(DECIMAL_BOUNDS[precision]) >= 0) {
throw new IllegalArgumentException(
"value " + value + " is out of range for Decimal(" + precision + ", " + scale + ")");
}
return truncated;
}
/**
* Encodes a timestamp into ClickHouse's {@code DateTime64(precision)} representation: a signed
* 64-bit integer counting ticks of size 10<sup>-precision</sup> seconds since the Unix epoch.
*
* <p>Accepts either a Joda {@link ReadableInstant} (millisecond precision) or a {@link
* java.time.Instant} (nanosecond precision). Sub-tick fractions are truncated toward negative
* infinity, matching ClickHouse's own encoding for negative timestamps.
*/
static long encodeDateTime64(Object value, int precision) {
long epochSecond;
int nanoOfSecond;
if (value instanceof java.time.Instant) {
java.time.Instant inst = (java.time.Instant) value;View on GitHub (pinned to 12126d8942)