vitessio/vitess · error
found no possible unique key on `%s`
Error message
found no possible unique key on `%s`
What it means
OnlineDDLMigrationTablesAnalysis (the schemadiff-based table-analysis step for online DDL) requires at least one usable unique key on both source and target tables to safely migrate rows. When PrioritizedUniqueKeys finds no primary key or unique index on the table, it aborts with this error naming the offending table.
Source
Thrown at go/vt/schemadiff/onlineddl.go:550
return columns.Filter(func(col *ColumnDefinitionEntity) bool {
return col.IsGenerated()
})
}
noDefaultColumns := func(columns *ColumnDefinitionEntityList) *ColumnDefinitionEntityList {
return columns.Filter(func(col *ColumnDefinitionEntity) bool {
return !col.HasDefault()
})
}
sourceColumns := sourceCreateTableEntity.ColumnDefinitionEntitiesList()
targetColumns := targetCreateTableEntity.ColumnDefinitionEntitiesList()
var droppedSourceNonGeneratedColumns *ColumnDefinitionEntityList
analysis.SourceSharedColumns, analysis.TargetSharedColumns, droppedSourceNonGeneratedColumns, analysis.SharedColumnsMap = AnalyzeSharedColumns(sourceColumns, targetColumns, alterTableAnalysis)
// unique keys
sourceUniqueKeys := PrioritizedUniqueKeys(sourceCreateTableEntity)
if sourceUniqueKeys.Len() == 0 {
return nil, fmt.Errorf("found no possible unique key on `%s`", sourceCreateTableEntity.Name())
}
targetUniqueKeys := PrioritizedUniqueKeys(targetCreateTableEntity)
if targetUniqueKeys.Len() == 0 {
return nil, fmt.Errorf("found no possible unique key on `%s`", targetCreateTableEntity.Name())
}
// VReplication supports completely different unique keys on source and target, covering
// some/completely different columns. The condition is that the key on source
// must use columns which all exist on target table.
eligibleSourceColumnsForUniqueKey := analysis.SourceSharedColumns.Union(generatedColumns(sourceColumns))
analysis.ChosenSourceUniqueKey = IterationKeysByColumns(sourceUniqueKeys, eligibleSourceColumnsForUniqueKey).First()
if analysis.ChosenSourceUniqueKey == nil {
return nil, fmt.Errorf("found no possible unique key on `%s` whose columns are in target table `%s`", sourceCreateTableEntity.Name(), targetCreateTableEntity.Name())
}
eligibleTargetColumnsForUniqueKey := analysis.TargetSharedColumns.Union(generatedColumns(targetColumns))
analysis.ChosenTargetUniqueKey = IterationKeysByColumns(targetUniqueKeys, eligibleTargetColumnsForUniqueKey).First()
if analysis.ChosenTargetUniqueKey == nil {View on GitHub (pinned to 01a25a7d17)
Solutions
- Add a primary key or unique key to the table before running the online migration (a separate plain ALTER).
- Ensure the ALTER statement itself doesn't drop the last unique key on the target definition.
- Use a non-online DDL strategy (e.g. direct/standard MySQL ALTER) if keylessness is intentional and acceptable.
Example fix
-- before (table has no unique key) ALTER TABLE mytable MODIFY col INT; -- after: add a key first ALTER TABLE mytable ADD COLUMN id BIGINT AUTO_INCREMENT PRIMARY KEY, MODIFY col INT;
Defensive patterns
Strategy: validation
Validate before calling
func hasUsableUniqueKey(cte *schemadiff.CreateTableEntity) bool {
return cte != nil && schemadiff.PrioritizedUniqueKeys(cte).Len() > 0
} Try / catch
analysis, err := schemadiff.OnlineDDLMigrationTablesAnalysis(...)
if err != nil {
return fmt.Errorf("cannot run online DDL for this table: %w", err)
} Prevention
- Enforce primary/unique keys on all tables managed by online DDL (schema policy).
- Review ALTERs that drop keys before submitting to online migration.
- Fall back to a direct ALTER strategy for keyless legacy tables.
When it happens
Trigger: Calling OnlineDDLMigrationTablesAnalysis (directly or via analyzeTables) for an ALTER on a table that has neither a PRIMARY KEY nor any UNIQUE key, for either the source or the target (post-ALTER) definition.
Common situations: Legacy heap tables created without keys; tables where the migration's ALTER drops the only unique key/primary key on the target definition; partitioned or imported tables missing constraints.
Related errors
- unexpected diff action
- unexpected table spec
- expected a CREATE TABLE statement
- Unknown online DDL strategy: '%v'
- --force-cut-over-after is only valid in 'vitess' strategy. F
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/c213b22660f64f87.
Report an issue: GitHub.