apache/seatunnel · error · SeaTunnelException

Incremental snapshot for tables requires primary key, but ta

Error message

Incremental snapshot for tables requires primary key, but table %s doesn't have primary key.

What it means

MySqlUtils.getSplitType derives the SeaTunnelRowType used for chunk splitting from the table's primary key, and throws a SeaTunnelException when the table has no primary key, because incremental snapshot chunking requires a unique, ordered key. The library fails fast instead of producing incorrect or duplicated snapshot chunks.

Source

Thrown at seatunnel-connectors-v2/connector-cdc/connector-cdc-mysql/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/mysql/utils/MySqlUtils.java:326

                }
            } else {
                for (int i = 0; i < primaryKeyNum; i++) {
                    statement.setObject(i + 1, splitStart[i]);
                    statement.setObject(i + 1 + primaryKeyNum, splitEnd[i]);
                    statement.setObject(i + 1 + 2 * primaryKeyNum, splitEnd[i]);
                }
            }
            return statement;
        } catch (Exception e) {
            throw new RuntimeException("Failed to build the split data read statement.", e);
        }
    }

    public static SeaTunnelRowType getSplitType(
            Table table, RelationalDatabaseConnectorConfig dbzConnectorConfig) {
        List<Column> primaryKeys = table.primaryKeyColumns();
        if (primaryKeys.isEmpty()) {
            throw new SeaTunnelException(
                    String.format(
                            "Incremental snapshot for tables requires primary key,"
                                    + " but table %s doesn't have primary key.",
                            table.id()));
        }

        // use first field in primary key as the split key
        return getSplitType(primaryKeys.get(0), dbzConnectorConfig);
    }

    public static BinlogOffset getBinlogPosition(SourceRecord dataRecord) {
        return getBinlogPosition(dataRecord.sourceOffset());
    }

    public static BinlogOffset getBinlogPosition(Map<String, ?> offset) {
        Map<String, String> offsetStrMap = new HashMap<>();
        for (Map.Entry<String, ?> entry : offset.entrySet()) {
            offsetStrMap.put(

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Add a primary key to the table (ALTER TABLE ... ADD PRIMARY KEY) and restart the job
  2. If adding a PK is impossible, exclude the table from the incremental-snapshot table list or use a non-incremental snapshot mode
  3. If a suitable unique NOT NULL column exists, add a PK on it
  4. Check table.id() in the message to identify exactly which table lacks the key

Example fix

// before
CREATE TABLE orders (id BIGINT, name VARCHAR(64));
// after
ALTER TABLE orders ADD PRIMARY KEY (id);
Defensive patterns

Strategy: validation

Validate before calling

ResultSet rs = st.executeQuery(
    "SELECT COUNT(*) FROM information_schema.table_constraints " +
    "WHERE table_schema=DATABASE() AND table_name='t' AND constraint_type='PRIMARY KEY'");
if (!rs.next() || rs.getLong(1) == 0) throw new IllegalStateException("PK required for incremental snapshot");

Try / catch

try {
    SeaTunnelRowType splitType = MySqlUtils.getSplitType(table, dbzConfig);
} catch (SeaTunnelException e) {
    // fall back to non-incremental snapshot or exclude table
}

Prevention

When it happens

Trigger: Calling getSplitType for a table whose primaryKeyColumns() is empty while incremental snapshot is enabled; typically a table created without PRIMARY KEY or with only a non-clustered unique key the connector doesn't treat as PK.

Common situations: Legacy tables without PKs added to a CDC table list; replica tables stripped of PKs; user assumes a UNIQUE index suffices but connector requires an actual primary key.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/74d3aadd7941a8ae. Report an issue: GitHub.