{"record":{"id":"57b703ae6f287ee4","repo":"apache/seatunnel","slug":"unsupported-type-s-for-numeric-minus","errorCode":null,"errorMessage":"Unsupported type %s for numeric minus.","messagePattern":"Unsupported type (.+?) for numeric minus\\.","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","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":75,"sourceCode":"            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(\n                    ((BigInteger) minuend).subtract((BigInteger) subtrahend).toString());\n        } else if (minuend instanceof BigDecimal) {\n            return ((BigDecimal) minuend).subtract((BigDecimal) subtrahend);\n        } else if (minuend instanceof String) {\n            return BigDecimal.valueOf(Long.MAX_VALUE);\n        } else {\n            throw new UnsupportedOperationException(\n                    String.format(\n                            \"Unsupported type %s for numeric minus.\",\n                            minuend.getClass().getSimpleName()));\n        }\n    }\n\n    /**\n     * Compares two comparable objects.\n     *\n     * @return The value {@code 0} if {@code num1} is equal to the {@code num2}; a value less than\n     *     {@code 0} if the {@code num1} is numerically less than the {@code num2}; and a value\n     *     greater than {@code 0} if the {@code num1} is numerically greater than the {@code num2}.\n     * @throws ClassCastException if the compared objects are not instance of {@link Comparable} or\n     *     not <i>mutually comparable</i> (for example, strings and integers).\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static int compare(Object obj1, Object obj2) {\n        Comparable<Object> c1 = (Comparable<Object>) obj1;","sourceCodeStart":57,"sourceCodeEnd":93,"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#L57-L93","documentation":"ObjectUtils.minus() supports subtraction only for Integer, Short, Byte, Long, BigInteger, BigDecimal and (specially) String. For any other operand type it throws UnsupportedOperationException with the offending simple class name. String operands short-circuit to Long.MAX_VALUE, so only truly unsupported types reach this branch.","triggerScenarios":"Calling ObjectUtils.minus() with two same-class operands whose type is not one of the supported numeric types, e.g. Float, Double, java.util.Date, or a custom class.","commonSituations":"Incremental snapshot on a table with a FLOAT/DOUBLE split key, so chunk offsets are Float/Double values which minus() cannot handle.","solutions":["Convert operands to BigDecimal before calling: ObjectUtils.minus(BigDecimal.valueOf(f1), BigDecimal.valueOf(f2)).","Choose a supported numeric type as the split key (integer or decimal column) for incremental snapshot tables.","If this arises inside SeaTunnel itself, upgrade or patch ObjectUtils to add the missing branch (e.g. Float/Double) since the plus() counterpart is similarly limited."],"exampleFix":"// before\nObject result = ObjectUtils.minus(floatVal1, floatVal2); // throws\n// after\nObject result = ObjectUtils.minus(\n        BigDecimal.valueOf((Float) floatVal1), BigDecimal.valueOf((Float) floatVal2));","handlingStrategy":"validation","validationCode":"static boolean isSupportedForMinus(Object o) {\n    return o instanceof Integer || o instanceof Short || o instanceof Byte\n        || o instanceof Long || o instanceof BigInteger || o instanceof BigDecimal\n        || o instanceof String;\n}","typeGuard":"if (!(o instanceof Number || o instanceof String)) {\n    throw new IllegalArgumentException(\"minus supports Number/String only: \" + o.getClass());\n}","tryCatchPattern":"try {\n    diff = ObjectUtils.minus(a, b);\n} catch (UnsupportedOperationException e) {\n    log.warn(\"falling back to BigDecimal subtraction\", e);\n    diff = BigDecimal.valueOf(((Number) a).doubleValue()).subtract(BigDecimal.valueOf(((Number) b).doubleValue()));\n}","preventionTips":["Avoid FLOAT/DOUBLE columns as incremental-snapshot split keys; prefer integer or decimal types","Convert to BigDecimal before invoking generic numeric utilities","Review supported types in ObjectUtils before reusing it outside CDC watermark logic"],"tags":["cdc","unsupported-type","numeric"],"backgroundTag":"unsupported-operation","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}