vitessio/vitess · error
VT12001
VT12001
Error message
'%s' column referenced in update expression '%s' is itself updated
What it means
VT12001 "'column' referenced in update expression 'expr' is itself updated" is panicked by errIfDependentColumnUpdated (go/vt/vtgate/planbuilder/operators/update.go:233), invoked from prepareUpdateExpressionList. For a multi-table UPDATE, each update expression's join-column dependencies are checked; if an expression assigned in the SET clause references (per ctx.SemTable.EqualsExprWithDeps) a column that the same update also modifies, the statement is rejected — MySQL semantics forbid reading a column being updated in the same statement. Vitess turns this into a planning-time error instead of producing a wrong plan.
Source
Thrown at go/vt/vtgate/planbuilder/operators/update.go:233
jc := breakExpressionInLHSandRHS(ctx, ue.Expr, exprDeps.Remove(target))
ueMap[target] = append(ueMap[target], updColumn{ue.Name, jc})
}
// Check if any of the dependent columns are updated in the same query.
// This can result in a mismatch of rows on how MySQL interprets it and how Vitess would have updated those rows.
// It is safe to fail for those cases.
errIfDependentColumnUpdated(ctx, upd, ueMap)
return ueMap
}
func errIfDependentColumnUpdated(ctx *plancontext.PlanningContext, upd *sqlparser.Update, ueMap map[semantics.TableSet]updList) {
for _, ue := range upd.Exprs {
for _, list := range ueMap {
for _, dc := range list {
for _, bvExpr := range dc.jc.LHSExprs {
if ctx.SemTable.EqualsExprWithDeps(ue.Name, bvExpr.Expr) {
panic(vterrors.VT12001(
fmt.Sprintf("'%s' column referenced in update expression '%s' is itself updated", sqlparser.String(ue.Name), sqlparser.String(dc.jc.Original))))
}
}
}
}
}
}
func createUpdateOpWithTarget(ctx *plancontext.PlanningContext, updStmt *sqlparser.Update, target semantics.TableSet, uList updList) dmlOp {
if len(uList) == 0 {
panic(vterrors.VT13001("no update expression for the target"))
}
ti, err := ctx.SemTable.TableInfoFor(target)
if err != nil {
panic(vterrors.VT13001(err.Error()))
}
vTbl := ti.GetVindexTable()View on GitHub (pinned to 01a25a7d17)
Solutions
- Restructure the UPDATE so the SET expressions do not read columns assigned in the same statement — compute the needed values first (e.g. into a temp table or derived table)
- Split the UPDATE into two sequential statements: one to materialize dependent values, one to apply them
- If the reference is unintentional, rename/qualify columns so the SET expression reads the pre-update source column from the other table only
Example fix
-- before (b is both read and written) UPDATE t1 JOIN t2 ON t1.id = t2.id SET t1.a = t2.b, t2.b = t2.b + 1; -- after (two statements) UPDATE t1 JOIN t2 ON t1.id = t2.id SET t1.a = t2.b; UPDATE t2 SET b = b + 1;
Defensive patterns
Strategy: validation
Validate before calling
-- verify no SET expression reads a column assigned in the same multi-table UPDATE SELECT column_name FROM information_schema.columns WHERE table_name = ? AND column_name IN (columns_read_by_set_expressions);
Try / catch
if err != nil && strings.Contains(err.Error(), "is itself updated") {
return splitIntoSequentialUpdates(ctx, stmt)
} Prevention
- Never SET a column and read that same column in another SET expression of the same UPDATE
- Split multi-table updates that feed values between tables into sequential statements
- Use a temp table or CTE to materialize values before updating
When it happens
Trigger: A multi-table UPDATE like UPDATE t1 JOIN t2 ... SET t1.a = t2.b WHERE ... where t2.b (the join/read column) is itself assigned elsewhere in the same UPDATE's Exprs; the check finds ue.Name equal-by-deps to a bvExpr in dc.jc.LHSExprs of an updated dependent column.
Common situations: Bulk updates written as self-referencing joins (SET t.x = t.y while t.y is also SET); migrations rewriting key columns that participate in the join condition; users porting application logic that assumed single-pass semantics.
Related errors
- VT13001
- no app indicated
- only integer literals are supported
- only the integer literal 1 is supported
- tablet %v type change %v -> %v is not an allowed transition
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/d0206951b4154899.
Report an issue: GitHub.