vitessio/vitess · error

a conflicting vindex named %s already exists in the source v

Error message

a conflicting vindex named %s already exists in the source vschema

What it means

During CreateLookupVindex, Vitess validates that the vindex name you are creating does not already exist in the source keyspace's vschema with a different definition. If a vindex with the same name exists but its type/params/owner differ from the one being created (compared via proto.Equal), creation is refused. If it exists with an identical definition, the call proceeds idempotently.

Source

Thrown at go/vt/wrangler/materializer.go:626

	}
	// If source and target keyspaces are same, Make vschemas point to the same object.
	if keyspace == targetKeyspace {
		targetVSchema = sourceVSchema
	} else {
		targetVSchema, err = wr.ts.GetVSchema(ctx, targetKeyspace)
		if err != nil {
			return nil, nil, nil, err
		}
	}
	if targetVSchema.Vindexes == nil {
		targetVSchema.Vindexes = make(map[string]*vschemapb.Vindex)
	}
	if targetVSchema.Tables == nil {
		targetVSchema.Tables = make(map[string]*vschemapb.Table)
	}
	if existing, ok := sourceVSchema.Vindexes[vindexName]; ok {
		if !proto.Equal(existing, vindex) {
			return nil, nil, nil, fmt.Errorf("a conflicting vindex named %s already exists in the source vschema", vindexName)
		}
	}
	sourceVSchemaTable = sourceVSchema.Tables[sourceTableName]
	if sourceVSchemaTable == nil {
		if !schema.IsInternalOperationTableName(sourceTableName) {
			return nil, nil, nil, fmt.Errorf("source table %s not found in vschema", sourceTableName)
		}
	}
	for _, colVindex := range sourceVSchemaTable.ColumnVindexes {
		// For a conflict, the vindex name and column should match.
		if colVindex.Name != vindexName {
			continue
		}
		colName := colVindex.Column
		if len(colVindex.Columns) != 0 {
			colName = colVindex.Columns[0]
		}
		if colName == sourceVindexColumns[0] {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Check the existing vindex with `vtctldclient GetVSchema <keyspace>` and either use a new, unique vindex name or delete/rename the conflicting one
  2. If the existing vindex is intentionally identical, re-run with the exact same spec so proto.Equal passes and the call is idempotent
  3. If the old vindex is no longer wanted, remove it and its ColumnVindex entry from the source vschema, then retry

Example fix

// before (conflicting redefinition)
{"name":"user_lookup","type":"consistent_lookup_unique","owner":"users"} // existing: type lookup, no owner
// after: pick a fresh name or match the existing definition exactly
{"name":"user_lookup_v2","type":"consistent_lookup_unique","owner":"users"}
Defensive patterns

Strategy: validation

Validate before calling

vs, _ := ts.GetVSchema(ctx, keyspace)
if existing, ok := vs.Vindexes[vindexName]; ok && !proto.Equal(existing, vindex) {
    return fmt.Errorf("vindex %s already exists with a different definition", vindexName)
}

Type guard

func hasConflictingVindex(vs *vschemapb.Keyspace, name string, want *vschemapb.Vindex) bool {
    existing, ok := vs.Vindexes[name]
    return ok && !proto.Equal(existing, want)
}

Try / catch

if err := wr.CreateLookupVindex(ctx, ks, vindex, tables, cols, owner, opts); err != nil {
    if strings.Contains(err.Error(), "conflicting vindex") {
        // reconcile vschema or pick a new vindex name
        return reconcileVindex(err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling CreateLookupVindex (vtctld `CreateLookupVindex` / `Materialize`) with a vindex whose name already exists in the source keyspace's vschema but was defined with a different type, params (e.g. data_type), or owner.

Common situations: Re-running an earlier CreateLookupVindex after editing the vindex JSON spec; two operators creating vindexes with colliding names; leftover vindex from a partially-completed earlier backfill with tweaked settings.

Related errors


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