{"record":{"id":"1fe65ae07ee5fc8a","repo":"apache/seatunnel","slug":"exactly-once-is-enabled-but-not-found-primary-key","errorCode":null,"errorMessage":"Exactly once is enabled, but not found primary key or unique key for table %s","messagePattern":"Exactly once is enabled, but not found primary key or unique key for table (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/source/enumerator/splitter/AbstractJdbcSourceChunkSplitter.java","lineNumber":87,"sourceCode":"                    \"Concurrent read is disabled for table {}, using single split without analysis.\",\n                    tableId);\n            return Collections.singletonList(\n                    createSnapshotSplit(null, tableId, 0, null, null, null));\n        }\n\n        try (JdbcConnection jdbc = dialect.openJdbcConnection(sourceConfig)) {\n            log.info(\"Start splitting table {} into chunks...\", tableId);\n            long start = System.currentTimeMillis();\n\n            Column splitColumn = getSplitColumn(jdbc, dialect, tableId);\n            log.info(\n                    \"Chosen split column {} for table {}\",\n                    splitColumn != null ? splitColumn.name() : \"null\",\n                    tableId);\n            List<SnapshotSplit> splits = new ArrayList<>();\n            if (splitColumn == null) {\n                if (sourceConfig.isExactlyOnce()) {\n                    throw new UnsupportedOperationException(\n                            String.format(\n                                    \"Exactly once is enabled, but not found primary key or unique key for table %s\",\n                                    tableId));\n                }\n                SnapshotSplit singleSplit = createSnapshotSplit(jdbc, tableId, 0, null, null, null);\n                splits.add(singleSplit);\n                log.warn(\n                        \"No evenly split column found for table {}, use single split {}\",\n                        tableId,\n                        singleSplit);\n            } else {\n                final List<ChunkRange> chunks;\n                try {\n                    chunks = splitTableIntoChunks(jdbc, tableId, splitColumn);\n                } catch (SQLException e) {\n                    throw new RuntimeException(\"Failed to split chunks for table \" + tableId, e);\n                }\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-base/src/main/java/org/apache/seatunnel/connectors/cdc/base/source/enumerator/splitter/AbstractJdbcSourceChunkSplitter.java#L69-L105","documentation":"Thrown by AbstractJdbcSourceChunkSplitter.generateSplits() when the table being snapshot has no primary key or usable unique key column to chunk on, while the source is configured for exactly-once. Without a split column, snapshot splits cannot be constructed deterministically, which conflicts with exactly-once guarantees, so the connector fails fast.","triggerScenarios":"generateSplits() finds splitColumn == null for the table AND sourceConfig.isExactlyOnce() is true; the connector then throws UnsupportedOperationException with the table id.","commonSituations":"Snapshotting a view or a table deliberately created without a PRIMARY KEY; older MySQL MyISAM tables without keys; exactly_once=true (default in many setups) left enabled while pointing at keyless tables.","solutions":["Add a primary key or a unique NOT NULL index to the table","Add a suitable unique column to the table that can serve as the split key","If approximate/duplicate-tolerant snapshot is acceptable, disable exactly-once mode in the connector config so a single full-table split is used","Change the captured table list to exclude the keyless table"],"exampleFix":"// before (config)\n//   exact_job: { MySQL-CDC: { \"exactly_once\": true, \"table-names\": [\"db.kv_no_pk\"] } }\n// after\n//   exact_job: { MySQL-CDC: { \"exactly_once\": false, \"table-names\": [\"db.kv_no_pk\"] } }\n// or: ALTER TABLE db.kv_no_pk ADD PRIMARY KEY (id);","handlingStrategy":"validation","validationCode":"// Ensure the table has a usable key before enabling exactly-once:\nSELECT TABLE_NAME, COUNT(*) AS keys FROM information_schema.KEY_TABLE_CONSTRAINTS\n WHERE TABLE_SCHEMA='db' AND TABLE_NAME='t' GROUP BY TABLE_NAME;\n// or: SHOW KEYS FROM db.t WHERE Key_name = 'PRIMARY';","typeGuard":null,"tryCatchPattern":"try { source.generateSplits(tableId); } catch (UnsupportedOperationException e) {\n    LOG.warn(\"Table {} has no PK/unique key; falling back to non-exactly-once\", tableId);\n}\n// Or in config: set exactly_once=false for keyless tables","preventionTips":["Enforce primary keys on all CDC-captured tables","Audit target tables for PK/unique keys before enabling exactly_once","Set exactly_once=false explicitly for known keyless tables"],"tags":["cdc","jdbc","primary-key","exactly-once","chunk-splitting"],"backgroundTag":"unsupported-operation","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"}