apache/seatunnel · error · RuntimeException

Invalid bytes for Decimal field

Error message

Invalid bytes for Decimal field

What it means

Debezium encodes DECIMAL fields either as plain JSON numbers or as a {scale, value} object whose 'value' is base64 binary representing the unscaled BigInteger. When converting a DecimalType field, the converter found binary/textual content that could not be interpreted as a valid unscaled integer (new BigInteger(value.binaryValue()) failed), and wraps the failure in RuntimeException("Invalid bytes for Decimal field").

Solutions

  1. Align Debezium's decimal.handling.mode with what the converter expects (connect mode with base64 encoded bytes) and re-capture data
  2. Inspect the raw JSON payload of the failing field to confirm the {scale,value} encoding
  3. Add upstream normalization so decimals always arrive as either numbers or {scale,value} objects
  4. If the source encoding is double/string, adjust the declared SeaTunnel schema type so a different converter branch runs

Example fix

// before: decimal.handling.mode=double -> plain JSON number reaches binary branch
"decimal.handling.mode": "double"
// after: keep binary/precise encoding
"decimal.handling.mode": "precise"
Defensive patterns

Strategy: validation

Validate before calling

JsonNode v = payload.get("decimalField");
boolean ok = v != null && (v.isNumber() || (v.isObject() && v.has("scale") && v.has("value")));
if (!ok) throw new IllegalArgumentException("Decimal field must be a number or {scale,value} object");

Try / catch

try {
    row = converter.parse(payload);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("Invalid bytes for Decimal")) {
        log.error("Check Debezium decimal.handling.mode; expected base64 {scale,value} encoding", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: getValue() hitting the DecimalType branch with a node where isBinary/isTextual is true but binaryValue() does not decode to a valid integer — corrupt or wrongly-encoded decimal payloads, or a JSON field that is textual but not the expected base64/binary representation.

Common situations: Decimal fields written by a different Debezium encoding mode (e.g. decimal.handling.mode=double producing plain numbers vs. base64 in the {scale,value} wrapper); schema evolution changing the field representation; hand-edited or replayed CDC payloads.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/debezium/DebeziumRowConverter.java:99

            case INT:
                return value.asInt();
            case BIGINT:
                return value.asLong();
            case FLOAT:
                return value.floatValue();
            case DOUBLE:
                return value.doubleValue();
            case DECIMAL:
                if (value.isNumber()) {
                    return value.decimalValue();
                }
                if (value.isBinary() || value.isTextual()) {
                    try {
                        return new BigDecimal(
                                new BigInteger(value.binaryValue()),
                                ((DecimalType) dataType).getScale());
                    } catch (Exception e) {
                        throw new RuntimeException("Invalid bytes for Decimal field", e);
                    }
                }
                if (value.has(DECIMAL_SCALE_KEY)) {
                    return new BigDecimal(
                            new BigInteger(value.get(DECIMAL_VALUE_KEY).binaryValue()),
                            value.get(DECIMAL_SCALE_KEY).intValue());
                }
                return new BigDecimal(value.asText());
            case STRING:
                return value.asText();
            case BYTES:
                try {
                    return value.binaryValue();
                } catch (IOException e) {
                    throw new RuntimeException("Invalid bytes field", e);
                }
            case DATE:
                String dateStr = value.asText();

View on GitHub (pinned to cf67b549a7)