apache/seatunnel · error · java.lang.IllegalStateException
Unsupported operand type, the minuend type %s is different w
Error message
Unsupported operand type, the minuend type %s is different with subtrahend type %s.
What it means
ObjectUtils.minus() computes minuend - subtrahend and requires both operands to be of exactly the same Java class. When the classes differ (checked with getClass().equals()), it throws this IllegalStateException. It is an internal invariant check used mainly by incremental-snapshot split logic when comparing high-watermark values.
Source
Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/utils/ObjectUtils.java:50
return Math.addExact((Integer) number, augend);
} else if (number instanceof Long) {
return Math.addExact((Long) number, augend);
} else if (number instanceof BigInteger) {
return ((BigInteger) number).add(BigInteger.valueOf(augend));
} else if (number instanceof BigDecimal) {
return ((BigDecimal) number).add(BigDecimal.valueOf(augend));
} else {
throw new UnsupportedOperationException(
String.format(
"Unsupported type %s for numeric plus.",
number.getClass().getSimpleName()));
}
}
/** Returns the difference {@code BigDecimal} whose value is {@code (minuend - subtrahend)}. */
public static BigDecimal minus(Object minuend, Object subtrahend) {
if (!minuend.getClass().equals(subtrahend.getClass())) {
throw new IllegalStateException(
String.format(
"Unsupported operand type, the minuend type %s is different with subtrahend type %s.",
minuend.getClass().getSimpleName(),
subtrahend.getClass().getSimpleName()));
}
if (minuend instanceof Integer) {
return BigDecimal.valueOf((int) minuend).subtract(BigDecimal.valueOf((int) subtrahend));
} else if (minuend instanceof Short) {
return BigDecimal.valueOf((short) minuend)
.subtract(BigDecimal.valueOf((short) subtrahend));
} else if (minuend instanceof Byte) {
return BigDecimal.valueOf((byte) minuend)
.subtract(BigDecimal.valueOf((byte) subtrahend));
} else if (minuend instanceof Long) {
return BigDecimal.valueOf((long) minuend)
.subtract(BigDecimal.valueOf((long) subtrahend));
} else if (minuend instanceof BigInteger) {
return new BigDecimal(View on GitHub (pinned to cf67b549a7)
Solutions
- Ensure both operands passed to minus() are the same runtime type; normalize numerics to a common type (e.g. BigDecimal) before calling.
- Inspect the two types named in the message and trace where each value originates (split start vs end offsets) to find the type divergence.
- If the mismatch comes from a JDBC driver type variance, coerce values at deserialization time so watermark offsets share one type.
Example fix
// before
Object diff = ObjectUtils minus -> ObjectUtils.minus(startOffset, endOffset);
// after
BigDecimal diff = ObjectUtils.minus(
new BigDecimal(((Number) startOffset).longValue()),
new BigDecimal(((Number) endOffset).longValue())); Defensive patterns
Strategy: type-guard
Validate before calling
// Java
static boolean canMinus(Object a, Object b) {
return a != null && b != null && a.getClass().equals(b.getClass());
} Type guard
if (a == null || b == null || !a.getClass().equals(b.getClass())) {
throw new IllegalArgumentException("minus operands must share one type, got "
+ (a == null ? "null" : a.getClass()) + " vs " + (b == null ? "null" : b.getClass()));
} Try / catch
try {
diff = ObjectUtils.minus(minuend, subtrahend);
} catch (IllegalStateException e) {
log.warn("operand type mismatch, normalizing to BigDecimal", e);
diff = ObjectUtils.minus(toBigDecimal(minuend), toBigDecimal(subtrahend));
} Prevention
- Normalize numeric offsets to a single type (BigDecimal/Long) at deserialization boundaries
- Unit-test split-key offsets across database drivers that report different numeric types
- Never pass raw Object watermarks around; wrap them in a typed offset class
When it happens
Trigger: Calling ObjectUtils.minus(a, b) where a and b are different types, e.g. an Integer minuend with a Long or BigDecimal subtrahend, as happens when CDC chunk-splitting compares watermark values read from different column type paths.
Common situations: A CDC table whose split key column values come back as different numeric types across splits (e.g. JDBC driver returning Long vs Integer depending on metadata), or custom code passing mixed numeric types to minus().
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unsupported operation type, the MIN value type %s is differe
- Unsupported type %s for numeric minus.
- Unable to convert to LocalDateTime from unexpected value ''
- Unable to convert to LocalDate from a java.sql.Time value '
- Unable to convert to LocalDate from unexpected value '' of t
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/205907ce8251b379.
Report an issue: GitHub.