[FLINK-38647][CDC] Improve error message for null before/after struct…#4439
[FLINK-38647][CDC] Improve error message for null before/after struct…#4439BreadS00 wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Improves diagnostics when Debezium before/after payload structs are unexpectedly null (common with PostgreSQL REPLICA IDENTITY DEFAULT/PRIMARY KEY), replacing an unhelpful downstream NullPointerException with a targeted message and an optional connector-specific hint.
Changes:
- Add explicit null checks for
before/afterstructs inDebeziumEventDeserializationSchema, throwing with a clearer message. - Introduce an overridable
getNullBeforeDataHint()hook for connector-specific guidance. - Provide a PostgreSQL-specific hint suggesting
REPLICA IDENTITY FULL.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| flink-cdc-connect/flink-cdc-source-connectors/flink-connector-debezium/src/main/java/org/apache/flink/cdc/debezium/event/DebeziumEventDeserializationSchema.java | Adds null checks for before/after and a hook for connector-specific hint text. |
| flink-cdc-connect/flink-cdc-pipeline-connectors/flink-cdc-pipeline-connector-postgres/src/main/java/org/apache/flink/cdc/connectors/postgres/source/PostgresEventDeserializer.java | Overrides the hint hook to provide a PostgreSQL-specific remediation suggestion. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (beforeValue == null) { | ||
| throw new NullPointerException( | ||
| "Before data is null for UPDATE/DELETE event. " | ||
| + formatHint(getNullBeforeDataHint()) | ||
| + "Schema name: " | ||
| + valueSchema.name()); | ||
| } |
There was a problem hiding this comment.
I wonder if we can throw a generic NPE in extractBeforeDataRecord, and wrap it in PostgresEventDeserializer like this?
// In PG event deserializer
@Override
private RecordData extractBeforeDataRecord(Struct value, Schema valueSchema) throws Exception {
try {
return super.extractBeforeDataRecord(value, valueSchema);
} catch (NullPointerException ape) {
// throw a wrapper exception here, indicating that one may forget to specify REPLICA IDENTITY PRIMARY mode
}
}or add extra checking like this:
private RecordData extractBeforeDataRecord(Struct value, Schema valueSchema) throws Exception {
Struct beforeValue = fieldStruct(value, Envelope.FieldName.BEFORE);
// Ensure we got proper UPDATE_BEFORE here
Preconditions.checkNotNull(beforeValue);
return super.extractBeforeDataRecord(value, valueSchema);
}WDYT?
| /** Connector-specific hint appended to the error message when before data is null. */ | ||
| protected String getNullBeforeDataHint() { | ||
| return ""; | ||
| } | ||
|
|
||
| /** | ||
| * Normalizes the hint string to a single trailing space so that overrides do not need to manage | ||
| * whitespace themselves. Returns an empty string when the hint is null or blank. | ||
| */ | ||
| private static String formatHint(String hint) { | ||
| if (hint == null) { | ||
| return ""; | ||
| } | ||
| String trimmed = hint.trim(); | ||
| return trimmed.isEmpty() ? "" : trimmed + " "; | ||
| } |
There was a problem hiding this comment.
I wonder if it's necessary to introduce new methods here just for error messages.
When PostgreSQL table uses default
REPLICA IDENTITY DEFAULTorREPLICA IDENTITY PRIMARY KEY, the logical decoding plugin (pgoutput) may not provide completebefore-datafor UPDATE events. This causes thebeforestruct to be null in Debezium events, leading to an unhelpfulNullPointerException.