vitessio/vitess · error
VT12001
VT12001
Error message
ON DUPLICATE KEY UPDATE with foreign keys with unique keys
What it means
INSERT ... ON DUPLICATE KEY UPDATE against a table that has foreign keys and declared unique keys is unsupported. The upsert planning path requires PK comparison and cannot safely handle unique-key interactions with FK verification, so it panics with VT12001.
Source
Thrown at go/vt/vtgate/planbuilder/operators/upsert.go:82
return inputs
}
func (u *Upsert) SetInputs(inputs []Operator) {
u.Sources = nil
u.setInputs(inputs)
}
func (u *Upsert) ShortDescription() string {
return ""
}
func (u *Upsert) GetOrdering(ctx *plancontext.PlanningContext) []OrderBy {
return nil
}
func createUpsertOperator(ctx *plancontext.PlanningContext, ins *sqlparser.Insert, insOp Operator, rows sqlparser.Values, vTbl *vindexes.BaseTable) Operator {
if len(vTbl.UniqueKeys) != 0 {
panic(vterrors.VT12001("ON DUPLICATE KEY UPDATE with foreign keys with unique keys"))
}
pIndexes, _ := findPKIndexes(vTbl, ins)
if len(pIndexes) == 0 {
// nothing to compare for update.
// Hence, only perform insert.
return insOp
}
upsert := &Upsert{}
for _, row := range rows {
var comparisons []sqlparser.Expr
for _, pIdx := range pIndexes {
var expr sqlparser.Expr
if pIdx.idx == -1 {
expr = pIdx.def
} else {
expr = row[pIdx.idx]View on GitHub (pinned to 01a25a7d17)
Solutions
- Remove the extra unique keys from the table, keeping only the primary key
- Perform the insert/update logic in the application: SELECT then INSERT or UPDATE explicitly
- Avoid managed FK mode for this table, or restructure so the upsert targets a table without unique keys
- If the unique key is unnecessary for correctness, drop it
Example fix
// before CREATE TABLE t (id INT PRIMARY KEY, email VARCHAR(64), UNIQUE KEY uq_email (email)); INSERT INTO t ... ON DUPLICATE KEY UPDATE ...; // after CREATE TABLE t (id INT PRIMARY KEY, email VARCHAR(64)); -- upsert handled in app or unique key dropped
Defensive patterns
Strategy: validation
Validate before calling
// before using upsert on a table with managed FKs
if len(table.UniqueKeys) > 0 && usesOnDuplicateKeyUpdate(stmt) {
return fmt.Errorf("upsert unsupported for %s: table has unique keys with FKs", table.Name)
} Try / catch
if err != nil && strings.Contains(err.Error(), "ON DUPLICATE KEY UPDATE with foreign keys with unique keys") {
// fall back to app-level select-then-insert/update
} Prevention
- Keep tables used for upserts free of extra unique keys when FKs are managed
- Implement insert-or-update logic in the application layer
- Review unique indexes before enabling foreign_key_mode
- Update Vitess: later releases may lift this restriction
When it happens
Trigger: createUpsertOperator is invoked for a table where vTbl.UniqueKeys is non-empty (table participates in FKs and has unique keys beyond the primary key) and the statement is an upsert.
Common situations: Tables with UNIQUE constraints used in upsert-heavy workloads after enabling managed foreign keys; migrating MySQL upserts to Vitess without revisiting unique indexes.
Related errors
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/6f9f8a1db29f115f.
Report an issue: GitHub.