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
- Compare the payload printed in the message against the configured row schema and fix the field types so JSON matches SeaTunnelRowType
- Set JsonDeserializationSchema option ignore-parse-errors = true so malformed rows are dropped (null returned) instead of failing the job
- Regenerate/refresh the rowType schema from the current source data format
- 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
- Keep the declared rowType in sync with the producer's JSON schema
- Enable ignore-parse-errors for topics with untrusted/dirty data
- Write a contract test that deserializes representative sample payloads
- Always inspect the cause chain to find the failing field converter
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)