apache/flink · error · UnsupportedOperationException
Unsupported operation '%s' for row kind.
Error message
Unsupported operation '%s' for row kind.
What it means
Thrown by CanalJsonSerializationSchema.rowKind2String when the row's RowKind is not INSERT, UPDATE_AFTER, UPDATE_BEFORE, or DELETE. Canal-JSON can only express INSERT ('INSERT') and DELETE ('DELETE') operations, so other row kinds have no mapping. Standard Flink RowKinds never hit this; it requires a custom or unusual RowKind value.
Source
Thrown at flink-formats/flink-json/src/main/java/org/apache/flink/formats/json/canal/CanalJsonSerializationSchema.java:102
ArrayData arrayData = new GenericArrayData(new RowData[] {row});
reuse.setField(0, arrayData);
reuse.setField(1, opType);
return jsonSerializer.serialize(reuse);
} catch (Throwable t) {
throw new RuntimeException("Could not serialize row '" + row + "'.", t);
}
}
private StringData rowKind2String(RowKind rowKind) {
switch (rowKind) {
case INSERT:
case UPDATE_AFTER:
return OP_INSERT;
case UPDATE_BEFORE:
case DELETE:
return OP_DELETE;
default:
throw new UnsupportedOperationException(
"Unsupported operation '" + rowKind + "' for row kind.");
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CanalJsonSerializationSchema that = (CanalJsonSerializationSchema) o;
return Objects.equals(jsonSerializer, that.jsonSerializer);
}
@Override
public int hashCode() {View on GitHub (pinned to 2f3c205e92)
Solutions
- Normalize RowKinds to the four standard kinds before the canal-json sink (e.g. map truncate to DELETE+INSERT pairs or filter)
- If custom verbs are required, switch the sink format to one that carries richer metadata (changelog-json style or raw JSON with a verb column)
- Guard the sink with a filter/mapping function that rejects or converts nonstandard kinds
Example fix
// before: custom kind flows into canal-json sink RowData out = new GenericRowData(RowKind.of((short) 5), ...); // nonstandard // after: normalize to a supported kind first RowData out = new GenericRowData(RowKind.DELETE, ...);
Defensive patterns
Strategy: validation
Validate before calling
RowKind k = row.getRowKind();
if (k != RowKind.INSERT && k != RowKind.UPDATE_BEFORE && k != RowKind.UPDATE_AFTER && k != RowKind.DELETE) {
throw new IllegalArgumentException("canal-json cannot encode " + k);
} Type guard
static boolean canalEncodable(RowKind k) {
return k == RowKind.INSERT || k == RowKind.UPDATE_BEFORE
|| k == RowKind.UPDATE_AFTER || k == RowKind.DELETE;
} Prevention
- Never create custom RowKind values feeding canal-json
- Map extra verbs to the four standard kinds upstream
When it happens
Trigger: A RowData carrying a RowKind outside the four standard kinds — e.g. a custom RowKind created via new RowKind(short) or an edit stream with additional verbs — being serialized with format 'canal-json'.
Common situations: Custom RowKind definitions in advanced CDC pipelines; upstream edit streams mapping extra verbs (truncate, upsert-special) onto nonstandard kinds; library code reusing RowKind ordinals incompatibly across versions.
Related errors
- Could not serialize row '%s'.
- Unsupported operation '%s' for row kind.
- Please invoke DeserializationSchema#deserialize(byte[], Coll
- Unknown "type" value "%s". The Canal JSON message is '%s'
- Corrupt Canal JSON message '%s'.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/ca83c780d823fdb6.
Report an issue: GitHub.