apache/seatunnel · error · SeaTunnelRuntimeException

COMMON-02

COMMON-02

Error message

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

What it means

The Json deserialization schema failed while converting a successfully-parsed JsonNode into a SeaTunnelRow using the runtime converter. The JSON text itself was readable, but its structure or value types did not match the configured SeaTunnelRowType (e.g. wrong field types, missing converters, coercion failures). Thrown as COMMON-02 JSON_OPERATION_FAILED with the offending payload embedded in the message.

Solutions

  1. Compare the payload printed in the message against the configured row schema and fix the field types so JSON matches SeaTunnelRowType
  2. Set JsonDeserializationSchema option ignore-parse-errors = true so malformed rows are dropped (null returned) instead of failing the job
  3. Regenerate/refresh the rowType schema from the current source data format
  4. Inspect the wrapped cause exception (getCause()) to identify which field converter failed

Example fix

// before
JsonDeserializationSchema schema = new JsonDeserializationSchema(rowType, false, false);
// after: tolerate bad rows instead of failing the pipeline
JsonDeserializationSchema schema = new JsonDeserializationSchema(rowType, true, false);
Defensive patterns

Strategy: try-catch

Validate before calling

// validate payload structure against rowType before deserialize
ObjectMapper om = new ObjectMapper();
JsonNode n = om.readTree(message);
if (!n.isObject() || n.size() != rowType.getTotalFields()) throw new IllegalArgumentException("payload does not match rowType: " + n);

Type guard

static boolean matchesRowType(JsonNode node, SeaTunnelRowType rowType) {
    if (!node.isObject()) return false;
    for (int i = 0; i < rowType.getTotalFields(); i++) {
        if (!node.has(rowType.getFieldName(i))) return false;
    }
    return true;
}

Try / catch

try {
    row = schema.deserialize(message);
} catch (SeaTunnelRuntimeException e) {
    if (e.getSeaTunnelErrorCode() == SeaTunnelErrorCode.JSON_OPERATION_FAILED) {
        log.warn("Skipping malformed record: {}", message);
        return; // dead-letter instead of failing job
    }
    throw e;
}

Prevention

When it happens

Trigger: JsonDeserializationSchema.deserialize() calls convertJsonNode(); runtimeConverter.convert(jsonNode, null) throws a RuntimeException because the JsonNode does not fit rowType (bad field types, incompatible nesting, converter coercion failure), and ignoreParseErrors is false.

Common situations: Upstream JSON schema drifted from the declared SeaTunnelRowType (int vs string fields); nested objects/arrays where flat rows were expected; a schema change in the source topic after the job was deployed; user forgot to enable ignoreParseErrors for dirty data.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/JsonDeserializationSchema.java:176

    public void setCollectorTablePath(SeaTunnelRow deserialize, CatalogTable catalogTable) {
        Optional<TablePath> tablePath =
                Optional.ofNullable(catalogTable).map(CatalogTable::getTablePath);
        if (tablePath.isPresent()) {
            deserialize.setTableId(tablePath.toString());
        }
    }

    private SeaTunnelRow convertJsonNode(JsonNode jsonNode) {
        if (jsonNode.isNull()) {
            return null;
        }
        try {
            return (SeaTunnelRow) runtimeConverter.convert(jsonNode, null);
        } catch (RuntimeException e) {
            if (ignoreParseErrors) {
                return null;
            }
            throw CommonError.jsonOperationError(FORMAT, jsonNode.toString(), e);
        }
    }

    public JsonNode deserializeToJsonNode(byte[] message) throws IOException {
        return objectMapper.readTree(message);
    }

    public SeaTunnelRow convertToRowData(JsonNode message) {
        return (SeaTunnelRow) runtimeConverter.convert(message, null);
    }

    private JsonNode convertBytes(byte[] message) {
        try {
            return objectMapper.readTree(message);
        } catch (IOException | RuntimeException e) {
            if (ignoreParseErrors) {
                return NullNode.getInstance();
            }

View on GitHub (pinned to cf67b549a7)