{"record":{"id":"37cf0a06e3fc9493","repo":"apache/seatunnel","slug":"unsupported-operation-37cf0a","errorCode":"UNSUPPORTED_OPERATION","errorMessage":"Unsupported operation ${rowKind} for row kind.","messagePattern":"Unsupported operation (.+?) for row kind\\.","errorType":"error_code","errorClass":"SeaTunnelJsonFormatException","httpStatus":null,"severity":"error","filePath":"seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/canal/CanalJsonSerializationSchema.java","lineNumber":115,"sourceCode":"            return jsonSerializer.serialize(reuse);\n        } catch (Throwable t) {\n            throw CommonError.jsonOperationError(FORMAT, row.toString(), t);\n        }\n    }\n\n    private String rowKind2String(RowKind rowKind) {\n        switch (rowKind) {\n            case INSERT:\n            case UPDATE_AFTER:\n                if (mergeUpdateEventFlag && rowKind.equals(RowKind.UPDATE_AFTER)) {\n                    return OP_UPDATE;\n                }\n                return OP_INSERT;\n            case UPDATE_BEFORE:\n            case DELETE:\n                return OP_DELETE;\n            default:\n                throw new SeaTunnelJsonFormatException(\n                        CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,\n                        String.format(\"Unsupported operation %s for row kind.\", rowKind));\n        }\n    }\n\n    private static SeaTunnelRowType createJsonRowType(SeaTunnelRowType databaseSchema) {\n        return new SeaTunnelRowType(\n                new String[] {\"old\", \"data\", \"type\", \"database\", \"table\", \"ts\"},\n                new SeaTunnelDataType[] {\n                    new ArrayType<>(SeaTunnelRowType[].class, databaseSchema),\n                    new ArrayType<>(SeaTunnelRowType[].class, databaseSchema),\n                    STRING_TYPE,\n                    STRING_TYPE,\n                    STRING_TYPE,\n                    LONG_TYPE\n                });\n    }\n}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/canal/CanalJsonSerializationSchema.java#L97-L133","documentation":"CanalJsonSerializationSchema maps a SeaTunnelRow's RowKind to a Canal JSON 'op' value (INSERT/UPDATE/DELETE). Only INSERT, UPDATE_BEFORE/UPDATE_AFTER and DELETE have Canal equivalents; any other RowKind (typically null or an unexpected kind) has no representation, so the serializer throws SeaTunnelJsonFormatException with UNSUPPORTED_OPERATION. Canal's CDC protocol simply cannot express such operations.","triggerScenarios":"Calling serialize(row) on a SeaTunnelRow whose RowKind is null or not one of INSERT, UPDATE_AFTER, UPDATE_BEFORE, DELETE — e.g. a row constructed without setRowKind, or emitted by a custom transform with an exotic kind.","commonSituations":"Custom sources/transforms that forget to call row.setRowKind(...); pipelines where an upstream change introduces a new RowKind not anticipated by a sink configured with format=canal-json; version upgrades adding new RowKind values.","solutions":["Ensure every row emitted upstream has setRowKind(INSERT|UPDATE_AFTER|UPDATE_BEFORE|DELETE) before reaching the sink","Fix the source/transform responsible for the unsupported RowKind","Switch the sink format away from canal-json if non-CDC row kinds are legitimately needed","Log row.getRowKind() at the sink boundary while debugging the pipeline"],"exampleFix":"// before\nSeaTunnelRow row = new SeaTunnelRow(fields); // RowKind never set -> null\n// after\nSeaTunnelRow row = new SeaTunnelRow(fields);\nrow.setRowKind(RowKind.INSERT); // or UPDATE_AFTER / UPDATE_BEFORE / DELETE","handlingStrategy":"validation","validationCode":"if (row.getRowKind() == null || !EnumSet.of(RowKind.INSERT, RowKind.UPDATE_AFTER, RowKind.UPDATE_BEFORE, RowKind.DELETE).contains(row.getRowKind())) {\n    throw new IllegalArgumentException(\"RowKind not serializable by canal-json: \" + row.getRowKind());\n}","typeGuard":"boolean isCanalSerializable(SeaTunnelRow row) {\n    RowKind k = row != null ? row.getRowKind() : null;\n    return k == RowKind.INSERT || k == RowKind.UPDATE_AFTER || k == RowKind.UPDATE_BEFORE || k == RowKind.DELETE;\n}","tryCatchPattern":null,"preventionTips":["Always call setRowKind on rows produced by custom sources/transforms","Unit-test serializers with one row per supported RowKind","Pin RowKind handling when upgrading SeaTunnel versions"],"tags":["cdc","rowkind","serialization","json-format"],"backgroundTag":"unsupported-operation","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}