vitessio/vitess · error

VT03015

VT03015

Error message

column has duplicate set values: '%v'

What it means

The SET clause of an UPDATE assigns a value to the same vindex column more than once (e.g. SET vcol = 1, vcol = 2). Vitess cannot evaluate a single value for the vindex mapping, so it panics with VT03015 reporting the duplicated column.

Source

Thrown at go/vt/vtgate/planbuilder/operators/update.go:1127

	return selExprs, offset
}

func createAssignmentExpressions(
	ctx *plancontext.PlanningContext,
	assignments []SetExpr,
	vcol sqlparser.IdentifierCI,
	subQueriesArgOnChangedVindex []string,
	vindexValueMap map[string]evalengine.Expr,
	compExprs []sqlparser.Expr,
) ([]string, []sqlparser.Expr) {
	// Searching in order of columns in colvindex.
	found := false
	for _, assignment := range assignments {
		if !vcol.Equal(assignment.Name.Name) {
			continue
		}
		if found {
			panic(vterrors.VT03015(assignment.Name.Name))
		}
		found = true
		pv, err := evalengine.Translate(assignment.Expr.EvalExpr, &evalengine.Config{
			ResolveType: ctx.TypeForExpr,
			Collation:   ctx.SemTable.Collation,
			Environment: ctx.VSchema.Environment(),
		})
		if err != nil {
			panic(invalidUpdateExpr(assignment.Name.Name.String(), assignment.Expr.EvalExpr))
		}

		if assignment.Expr.Info != nil {
			sqe, ok := assignment.Expr.Info.(SubQueryExpression)
			if ok {
				for _, sq := range sqe {
					subQueriesArgOnChangedVindex = append(subQueriesArgOnChangedVindex, sq.ArgName)
				}
			}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Remove duplicate assignments so each vindex column appears at most once in SET
  2. Deduplicate SET clauses when building SQL dynamically
  3. Last assignment wins in MySQL, so keep only the final intended assignment

Example fix

// before
UPDATE t SET vk = 1, vk = 2 WHERE id = 3;
// after
UPDATE t SET vk = 2 WHERE id = 3;
Defensive patterns

Strategy: validation

Validate before calling

// deduplicate SET targets before executing
seen := map[string]bool{}
for _, a := range stmt.Exprs {
    name := a.Name.Name.String()
    if seen[name] {
        return fmt.Errorf("duplicate SET assignment for %s", name)
    }
    seen[name] = true
}

Try / catch

if err != nil && strings.Contains(err.Error(), "duplicate set values") {
    // rebuild the UPDATE with deduplicated SET clause
}

Prevention

When it happens

Trigger: createAssignmentExpressions finds two assignments for the same virtual/vindex column while iterating the UPDATE's assignments.

Common situations: Dynamically generated UPDATE statements appending SET clauses; ORMs concatenating partial updates; hand-written SQL with accidental duplicate assignments.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/73561644dec7ea6e. Report an issue: GitHub.