{"record":{"id":"205907ce8251b379","repo":"apache/seatunnel","slug":"unsupported-operand-type-the-minuend-type-s-is-d","errorCode":null,"errorMessage":"Unsupported operand type, the minuend type %s is different with subtrahend type %s.","messagePattern":"Unsupported operand type, the minuend type (.+?) is different with subtrahend type (.+?)\\.","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/utils/ObjectUtils.java","lineNumber":50,"sourceCode":"            return Math.addExact((Integer) number, augend);\n        } else if (number instanceof Long) {\n            return Math.addExact((Long) number, augend);\n        } else if (number instanceof BigInteger) {\n            return ((BigInteger) number).add(BigInteger.valueOf(augend));\n        } else if (number instanceof BigDecimal) {\n            return ((BigDecimal) number).add(BigDecimal.valueOf(augend));\n        } else {\n            throw new UnsupportedOperationException(\n                    String.format(\n                            \"Unsupported type %s for numeric plus.\",\n                            number.getClass().getSimpleName()));\n        }\n    }\n\n    /** Returns the difference {@code BigDecimal} whose value is {@code (minuend - subtrahend)}. */\n    public static BigDecimal minus(Object minuend, Object subtrahend) {\n        if (!minuend.getClass().equals(subtrahend.getClass())) {\n            throw new IllegalStateException(\n                    String.format(\n                            \"Unsupported operand type, the minuend type %s is different with subtrahend type %s.\",\n                            minuend.getClass().getSimpleName(),\n                            subtrahend.getClass().getSimpleName()));\n        }\n        if (minuend instanceof Integer) {\n            return BigDecimal.valueOf((int) minuend).subtract(BigDecimal.valueOf((int) subtrahend));\n        } else if (minuend instanceof Short) {\n            return BigDecimal.valueOf((short) minuend)\n                    .subtract(BigDecimal.valueOf((short) subtrahend));\n        } else if (minuend instanceof Byte) {\n            return BigDecimal.valueOf((byte) minuend)\n                    .subtract(BigDecimal.valueOf((byte) subtrahend));\n        } else if (minuend instanceof Long) {\n            return BigDecimal.valueOf((long) minuend)\n                    .subtract(BigDecimal.valueOf((long) subtrahend));\n        } else if (minuend instanceof BigInteger) {\n            return new BigDecimal(","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/utils/ObjectUtils.java#L32-L68","documentation":"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.","triggerScenarios":"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.","commonSituations":"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().","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."],"exampleFix":"// before\nObject diff = ObjectUtils minus -> ObjectUtils.minus(startOffset, endOffset);\n// after\nBigDecimal diff = ObjectUtils.minus(\n        new BigDecimal(((Number) startOffset).longValue()),\n        new BigDecimal(((Number) endOffset).longValue()));","handlingStrategy":"type-guard","validationCode":"// Java\nstatic boolean canMinus(Object a, Object b) {\n    return a != null && b != null && a.getClass().equals(b.getClass());\n}","typeGuard":"if (a == null || b == null || !a.getClass().equals(b.getClass())) {\n    throw new IllegalArgumentException(\"minus operands must share one type, got \"\n        + (a == null ? \"null\" : a.getClass()) + \" vs \" + (b == null ? \"null\" : b.getClass()));\n}","tryCatchPattern":"try {\n    diff = ObjectUtils.minus(minuend, subtrahend);\n} catch (IllegalStateException e) {\n    log.warn(\"operand type mismatch, normalizing to BigDecimal\", e);\n    diff = ObjectUtils.minus(toBigDecimal(minuend), toBigDecimal(subtrahend));\n}","preventionTips":["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"],"tags":["cdc","type-mismatch","numeric"],"backgroundTag":"type-mismatch","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}