{"record":{"id":"42e63c3f71fec469","repo":"apache/seatunnel","slug":"the-before-field-of-s-operation-message-is-null","errorCode":null,"errorMessage":"The \"before\" field of %s operation message is null, if you are using Ogg Postgres Connector, please check the Postgres table has been set REPLICA IDENTITY to FULL level.","messagePattern":"The \"before\" field of (.+?) operation message is null, if you are using Ogg Postgres Connector, please check the Postgres table has been set REPLICA IDENTITY to FULL level\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/ogg/OggJsonDeserializationSchema.java","lineNumber":183,"sourceCode":"            }\n            switch (op) {\n                case OP_INSERT:\n                    // Gets the data for the INSERT operation\n                    JsonNode dataInsert = jsonNode.get(DATA_AFTER);\n                    SeaTunnelRow row = convertJsonNode(dataInsert);\n                    if (tablePath != null) {\n                        row.setTableId(tablePath.toString());\n                    }\n                    if (tsNode != null) {\n                        MetadataUtil.setEventTime(row, ts);\n                    }\n                    out.collect(row);\n                    break;\n                case OP_UPDATE:\n                    JsonNode dataBefore = jsonNode.get(DATA_BEFORE);\n                    // Modify Operation Data cannot be empty before modification\n                    if (dataBefore == null || dataBefore.isNull()) {\n                        throw new IllegalStateException(\n                                String.format(REPLICA_IDENTITY_EXCEPTION, \"UPDATE\"));\n                    }\n                    JsonNode dataAfter = jsonNode.get(DATA_AFTER);\n                    // Gets the data for the UPDATE BEFORE operation\n                    SeaTunnelRow before = convertJsonNode(dataBefore);\n                    // Gets the data for the UPDATE AFTER operation\n                    SeaTunnelRow after = convertJsonNode(dataAfter);\n                    before.setRowKind(RowKind.UPDATE_BEFORE);\n                    if (tablePath != null) {\n                        before.setTableId(tablePath.toString());\n                    }\n                    if (tsNode != null) {\n                        MetadataUtil.setEventTime(before, ts);\n                    }\n\n                    after.setRowKind(RowKind.UPDATE_AFTER);\n                    if (tablePath != null) {\n                        after.setTableId(tablePath.toString());","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-formats/seatunnel-format-json/src/main/java/org/apache/seatunnel/format/json/ogg/OggJsonDeserializationSchema.java#L165-L201","documentation":"For an Ogg UPDATE event, both the before and after images are required (SeaTunnel emits UPDATE_BEFORE/UPDATE_AFTER rows). When the JSON message lacks a non-null \"before\" (DATA_BEFORE) node, deserializeMessage throws IllegalStateException with REPLICA_IDENTITY_EXCEPTION telling the user to set REPLICA IDENTITY FULL — because the source database isn't publishing the old row image.","triggerScenarios":"deserialize → deserializeMessage handles case OP_UPDATE; jsonNode.get(DATA_BEFORE) returns null or an isNull() node because the upstream Ogg message for UPDATE contains only the \"after\" data.","commonSituations":"Oracle via Ogg without supplemental logging of all columns; Ogg Postgres connector where the table's REPLICA IDENTITY is DEFAULT (only PK in before image) or NOTHING; tables without primary keys; Ogg parameterization omitting before-images.","solutions":["For Postgres: run ALTER TABLE <table> REPLICA IDENTITY FULL; for Oracle: enable supplemental log data (ALL) at table level","Adjust Ogg/extract configuration to include before-images in the trail records","If before-images cannot be enabled, skip or down-convert updates (e.g. treat as insert-only) with custom handling","Verify the actual Ogg JSON payload has a populated \"before\" object for updates"],"exampleFix":"// before\nALTER TABLE mytable REPLICA IDENTITY DEFAULT;\n// after\nALTER TABLE mytable REPLICA IDENTITY FULL;","handlingStrategy":"validation","validationCode":"// verify before-images are published (Postgres)\n// SELECT relreplident FROM pg_class WHERE relname = 'mytable'; -- must be 'f' (FULL)\nJsonNode before = root.get(\"before\");\nif (before == null || before.isNull()) {\n    log.error(\"UPDATE missing before-image; enable REPLICA IDENTITY FULL\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    schema.deserialize(message, out);\n} catch (IllegalStateException e) {\n    log.error(\"Replica identity misconfigured: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Run ALTER TABLE ... REPLICA IDENTITY FULL on all CDC'd Postgres tables","Enable full supplemental logging on Oracle sources","Verify before-image presence in a sample Ogg message before deploying"],"tags":["ogg","cdc","postgres","replica-identity"],"backgroundTag":"missing-required-argument","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}