{"record":{"id":"9f9a060470e8ce4c","repo":"apache/seatunnel","slug":"non-heartbeat-record-has-no-documentkey-field-thi","errorCode":null,"errorMessage":"Non-heartbeat record has no documentKey field, this is unexpected. Record: {}","messagePattern":"Non-heartbeat record has no documentKey field, this is unexpected\\. Record: (.+?)","errorType":"console","errorClass":"MongodbConnectorException","httpStatus":null,"severity":"critical","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-mongodb/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/mongodb/source/fetch/MongodbFetchTaskContext.java","lineNumber":178,"sourceCode":"    }\n\n    @Override\n    public boolean isDataChangeRecord(SourceRecord record) {\n        return MongodbRecordUtils.isDataChangeRecord(record);\n    }\n\n    @Override\n    public boolean isRecordBetween(\n            SourceRecord record, @Nonnull Object[] splitStart, @Nonnull Object[] splitEnd) {\n        BsonDocument documentKey = getDocumentKey(record);\n        if (documentKey == null) {\n            if (isHeartbeatEvent(record)) {\n                log.debug(\n                        \"Heartbeat record has no documentKey field, skipping range check. Record: {}\",\n                        record);\n                return false;\n            }\n            log.warn(\n                    \"Non-heartbeat record has no documentKey field, this is unexpected. Record: {}\",\n                    record);\n            throw new MongodbConnectorException(\n                    ILLEGAL_ARGUMENT,\n                    \"Record has no documentKey field but is not a heartbeat event. \"\n                            + \"This indicates an unexpected record type: \"\n                            + record);\n        }\n        BsonDocument splitKeys = (BsonDocument) splitStart[0];\n        String firstKey = splitKeys.getFirstKey();\n        BsonValue keyValue = documentKey.get(firstKey);\n        BsonValue lowerBound = ((BsonDocument) splitStart[1]).get(firstKey);\n        BsonValue upperBound = ((BsonDocument) splitEnd[1]).get(firstKey);\n\n        if (isFullRange(lowerBound, upperBound)) {\n            return true;\n        }\n","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-mongodb/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/mongodb/source/fetch/MongodbFetchTaskContext.java#L160-L196","documentation":"MongodbFetchTaskContext.isRecordBetween performs resume-token-based range checks on change stream documents and requires every non-heartbeat event to carry a documentKey field. When a record lacks documentKey but is also not recognized as a heartbeat event, the connector cannot classify it, logs the warning, and throws MongodbConnectorException(ILLEGAL_ARGUMENT) with this message. This is an internal invariant: known Debezium/MongoDB event types (insert/update/delete/replace, DDL, heartbeat) always either have documentKey or are heartbeats.","triggerScenarios":"isRecordBetween() receives a Document with no 'documentKey' field and isHeartbeatEvent(record) returns false — i.e. an unexpected change stream event type (unrecognized op type, malformed driver-converted document, third-party writer inserting events with missing fields, or connector/driver version mismatch producing a record shape the code doesn't know).","commonSituations":"Upgrading MongoDB server or driver to a version emitting new event types (e.g. new DDL/change-stream events) while the connector's isHeartbeatEvent/record parsing predates them; custom aggregation pipeline in the change stream that strips documentKey from events; corrupted or hand-crafted change events; mixing connector versions (older fetch task against newer record format).","solutions":["Upgrade the SeaTunnel MongoDB CDC connector to a version whose event handling matches your MongoDB server/driver version","Remove or fix any custom change stream pipeline (e.g. $project/$match stages) that could strip the documentKey field from emitted events","Inspect the logged Record value to identify the unexpected op/event type and confirm it is legitimate; if it is a known new event type, patch isHeartbeatEvent/record classification to handle it","Verify no external writers are injecting malformed documents into the watched collection/change stream"],"exampleFix":"// before (record classification misses the new event type)\nif (isHeartbeatEvent(record)) { ... return false; }\nthrow new MongodbConnectorException(ILLEGAL_ARGUMENT, \"Record has no documentKey field...\");\n// after (handle the unexpected type gracefully)\nif (isHeartbeatEvent(record)) { return false; }\nif (isKnownNonDocumentEvent(record)) { return false; } // e.g. DDL/invalidate events\nlog.warn(\"Skipping record without documentKey: {}\", record);\nreturn false;","handlingStrategy":"try-catch","validationCode":"// Classify the record before calling range checks\nboolean isClassifiable(Document record) {\n    return record.containsKey(\"documentKey\")\n        || record.containsKey(\"id\") /* heartbeat */\n        || KNOWN_NON_DOCUMENT_EVENT_TYPES.contains(record.getString(\"operation\"));\n}","typeGuard":"boolean hasDocumentKey(Document record) {\n    return record != null && record.containsKey(\"documentKey\");\n}","tryCatchPattern":"try {\n    boolean inRange = isRecordBetween(record);\n} catch (MongodbConnectorException e) {\n    if (e.getErrorCode() == ILLEGAL_ARGUMENT && e.getMessage().contains(\"documentKey\")) {\n        log.warn(\"Skipping unclassifiable change stream record: {}\", record);\n        return; // skip, do not crash the pipeline\n    }\n    throw e;\n}","preventionTips":["Keep connector and MongoDB driver/server versions aligned; new change stream event types appear in newer servers","Avoid custom change stream aggregation pipelines that strip documentKey from events","Log the full offending record (the connector already logs it) and check the 'operation' field when this occurs","Pin and test the connector against your exact MongoDB version before production rollout"],"tags":["mongodb","cdc","change-stream","invariant","unexpected-record"],"backgroundTag":"unexpected-api-response-shape","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"}