apache/seatunnel · error · SeaTunnelRuntimeException

COMMON-02

COMMON-02

Error message

Json JSON convert/parse '<payload>' operation failed.

What it means

MaxWellJsonSerializationSchema.serialize wraps any Throwable from building the Maxwell envelope row and JSON-serializing it into jsonOperationError. The offending SeaTunnelRow's toString is embedded. It means the row does not match the Maxwell JSON row type (database/table/type/ts/data/old/xid style fields) or Jackson cannot serialize a value.

Solutions

  1. Compare row.toString() with the Maxwell JSON schema and fix the producing operator so arity/types match
  2. Ensure EVENT_TIME option value is a JSON-serializable scalar (string/long)
  3. Align the database schema passed to the serializer with the real data columns
  4. Write a unit test serializing the exact failing row to pinpoint the non-conforming field

Example fix

// before: option carries a LocalDateTime
row.getOptions().put("EVENT_TIME", LocalDateTime.now());
// after: store serializable millis
row.getOptions().put("EVENT_TIME", System.currentTimeMillis());
Defensive patterns

Strategy: validation

Validate before calling

if (row.getArity() != maxwellType.getTotalFields()) {
    throw new IllegalArgumentException("Maxwell row arity mismatch: " + row);
}
Object ts = row.getOptions() == null ? null : row.getOptions().get("EVENT_TIME");
boolean tsOk = ts == null || ts instanceof String || ts instanceof Long;

Type guard

boolean matchesMaxwellSchema(SeaTunnelRow row, SeaTunnelRowType t) {
    return row != null && row.getArity() == t.getTotalFields();
}

Try / catch

try {
    byte[] out = serializer.serialize(row);
} catch (SeaTunnelRuntimeException e) {
    log.error("Maxwell serialize failed for {}", row, e);
    throw e;
}

Prevention

When it happens

Trigger: serialize(SeaTunnelRow) receives a row whose arity or field types differ from the Maxwell schema built by createJsonRowType, or whose EVENT_TIME option / data fields are not JSON-serializable.

Common situations: Using a Maxwell-format sink after a transform altered field count/types; event-time option holding an unsupported object; mismatch between declared database schema and actual incoming rows; null reuse-row state after a failed earlier serialize.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/maxwell/MaxWellJsonSerializationSchema.java:95

            if (mergeUpdateEventFlag && row.getRowKind() == RowKind.UPDATE_AFTER) {
                reuse.setField(0, cacheUpdateBeforeRow);
            } else {
                reuse.setField(0, null);
            }

            reuse.setField(1, row);
            reuse.setField(2, rowKind2String(row.getRowKind()));
            if (!StringUtils.isEmpty(row.getTableId())) {
                reuse.setField(3, TablePath.of(row.getTableId()).getDatabaseName());
                reuse.setField(4, TablePath.of(row.getTableId()).getTableName());
            }
            if (row.getOptions() != null && row.getOptions().containsKey(EVENT_TIME.getName())) {
                reuse.setField(5, row.getOptions().get(EVENT_TIME.getName()));
            }
            return jsonSerializer.serialize(reuse);
        } catch (Throwable t) {
            throw CommonError.jsonOperationError(FORMAT, row.toString(), t);
        }
    }

    private String rowKind2String(RowKind rowKind) {
        switch (rowKind) {
            case INSERT:
            case UPDATE_AFTER:
                if (mergeUpdateEventFlag && rowKind.equals(RowKind.UPDATE_AFTER)) {
                    return OP_UPDATE;
                }
                return OP_INSERT;
            case UPDATE_BEFORE:
            case DELETE:
                return OP_DELETE;
            default:
                throw new SeaTunnelJsonFormatException(
                        CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
                        String.format("Unsupported operation %s for row kind.", rowKind));

View on GitHub (pinned to cf67b549a7)