apache/seatunnel · error · IllegalStateException
Null data value '${jsonNode}' Cannot send downstream
Error message
Null data value '${jsonNode}' Cannot send downstream What it means
When a Canal JSON event carries a null or JSON-null 'data' node, the deserializer normally skips query/create/alter DDL events, but for any other op type a null data value cannot produce a row, so it throws IllegalStateException to make the malformed/unsupported event visible rather than emitting an empty row downstream.
Source
Thrown at seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/canal/CanalJsonDeserializationSchema.java:150
if (database != null
&& !databasePattern.matcher(jsonNode.get(FIELD_DATABASE).asText()).matches()) {
return;
}
if (table != null
&& !tablePattern.matcher(jsonNode.get(FIELD_TABLE).asText()).matches()) {
return;
}
JsonNode dataNode = jsonNode.get(FIELD_DATA);
String op = jsonNode.get(FIELD_TYPE).asText();
JsonNode tsNode = jsonNode.get(FIELD_TS);
// When a null value is encountered, an exception needs to be thrown for easy sensing
if (dataNode == null || dataNode.isNull()) {
// We'll skip the query or create or alter event data
if (OP_QUERY.equals(op) || OP_CREATE.equals(op) || OP_ALTER.equals(op)) {
return;
}
throw new IllegalStateException(
format("Null data value '%s' Cannot send downstream", jsonNode));
}
switch (op) {
case OP_INSERT:
for (int i = 0; i < dataNode.size(); i++) {
SeaTunnelRow row = convertJsonNode(dataNode.get(i));
if (tablePath != null && !tablePath.toString().isEmpty()) {
row.setTableId(tablePath.toString());
}
if (tsNode != null) {
MetadataUtil.setEventTime(row, tsNode.asLong());
}
out.collect(row);
}
break;
case OP_UPDATE:
final ArrayNode oldNode = (ArrayNode) jsonNode.get(FIELD_OLD);View on GitHub (pinned to cf67b549a7)
Solutions
- Filter out non-data events (heartbeat/ROTATE/control events) before deserialization, e.g. only pass op INSERT/UPDATE/DELETE messages
- Skip events where data is null in custom logic by pre-checking the JSON, or patch the deserializer to ignore them like QUERY/CREATE/ALTER
- Check Canal server configuration to stop emitting heartbeat/control messages to the consumed channel
- Set table/database pattern filters (tablePattern/databasePattern) so unrelated events don't reach this code path
Example fix
// before
{"data":null,"op":"UNKNOWN","es":1699999999,...}
// after (pre-filter)
if (node.path("op").asText("").matches("INSERT|UPDATE|DELETE")
&& !node.path("data").isNull()) {
canalJsonSchema.deserialize(bytes, out);
} Defensive patterns
Strategy: validation
Validate before calling
JsonNode op = node.path("op");
JsonNode data = node.path("data");
boolean isDdl = op.asText("").matches("QUERY|CREATE|ALTER");
if (!isDdl && (data.isMissingNode() || data.isNull())) {
return; // skip non-data event before deserializing
} Type guard
boolean hasData = node.has("data") && !node.get("data").isNull() && node.get("data").isArray(); Try / catch
try { canalJsonSchema.deserialize(message, out); } catch (IllegalStateException e) { if (e.getMessage().startsWith("Null data value")) { /* skip heartbeat/control event */ } else { throw e; } } Prevention
- Filter heartbeat/DDL/control events before deserialization
- Configure Canal to not forward control messages to the consumed queue
- Apply database/table pattern filters so only data events are consumed
- Monitor for Canal version changes that alter event payloads
When it happens
Trigger: Consuming a Canal (MySQL binlog) JSON message whose op is not QUERY/CREATE/ALTER but whose data field is null or null-literal (e.g. heartbeats, some DELETE/other events with no data payload).
Common situations: Canal server heartbeat or control messages mixed into the monitored queue/topic; binlog events such as ROTATE or unsupported event types forwarded by Canal; filtering not applied upstream on message types.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Unknown operation type '${op}'.
- COMMON-02
- ILLEGAL_ARGUMENT
- Please invoke DeserializationSchema#deserialize(byte[], Coll
- Unsupported type: %s
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/84398a80c03818a3.
Report an issue: GitHub.