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

  1. Ensure both operands passed to minus() are the same runtime type; normalize numerics to a common type (e.g. BigDecimal) before calling.
  2. Inspect the two types named in the message and trace where each value originates (split start vs end offsets) to find the type divergence.
  3. 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

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


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/205907ce8251b379. Report an issue: GitHub.