vitessio/vitess · error
vindex has no owner
Error message
vindex has no owner
What it means
validateExternalizedVindex requires that a vindex being externalized has an owner. An ownerless vindex cannot be safely taken over by the lookup vindex workflow, since ownership determines who maintains lookup rows during writes, so the check fails with this error.
Source
Thrown at go/vt/vtctl/workflow/lookup_vindex.go:632
}
}
if targetVindex == nil {
err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "column %s not found in target schema %s",
sourceVindexColumn, sourceTableDefinition.Schema)
return
}
return
}
// validateExternalizedVindex checks if a given vindex is externalized.
// A vindex is considered externalized if it has an owner and is not in write-only mode.
func (lv *lookupVindex) validateExternalizedVindex(vindex *vschemapb.Vindex) error {
writeOnly, ok := vindex.Params["write_only"]
if ok && writeOnly == "true" {
return errors.New("vindex is in write-only mode")
}
if vindex.Owner == "" {
return errors.New("vindex has no owner")
}
return nil
}
// validateExternalized checks if the vindexes have been externalized
// and verifies the state of the VReplication workflow on the target shards.
// It ensures that all streams in the workflow are frozen.
func (lv *lookupVindex) validateExternalized(ctx context.Context, vindexByName map[string]*vschemapb.Vindex, workflowName string, targetShards []*topo.ShardInfo) error {
for vindexName, vindex := range vindexByName {
if err := lv.validateExternalizedVindex(vindex); err != nil {
return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "vindex %s has not been externalized yet: %v", vindexName, err)
}
}
err := forAllShards(targetShards, func(targetShard *topo.ShardInfo) error {
targetPrimary, err := lv.ts.GetTablet(ctx, targetShard.PrimaryAlias)
if err != nil {
return errView on GitHub (pinned to 01a25a7d17)
Solutions
- Pass the owner table (e.g. --owner user) when creating the lookup vindex so ownership is set
- Set the "owner" field on the vindex in the target keyspace's vschema, or remove/recreate the vindex properly
- If the vindex is intentionally unowned, do not run the externalization workflow for it; use plain Materialize instead
Example fix
// before
vtctldclient CreateLookupVindex --target-keyspace lookup commerce "{'vindexes': {...}}"
// after
vtctldclient CreateLookupVindex --target-keyspace lookup --owner-table user --owner-column id commerce "{'vindexes': {...}}" Defensive patterns
Strategy: validation
Validate before calling
v, _ := ts.GetVSchema(ctx, targetKS)
if vi := v.Vindexes[vindexName]; vi != nil && vi.Owner == "" {
return fmt.Errorf("vindex %s has no owner; pass owner table/column or set vschema owner", vindexName)
} Type guard
func hasOwner(v *vschemapb.Vindex) bool { return v.Owner != "" } Try / catch
if err := lv.validateExternalized(ctx, targetShards); err != nil {
if strings.Contains(err.Error(), "no owner") {
return fmt.Errorf("recreate the vindex with --owner set: %w", err)
}
return err
} Prevention
- Always pass the owner table when creating owned lookup vindexes
- Never hand-edit vschema owner fields without verifying them
- Run a pre-flight GetVSchema check before externalization workflows
When it happens
Trigger: Running CreateLookupVindex externalization against a vindex whose Vindex.Owner field is empty — the vindex exists in the target vschema but has no owner column vindex association and write_only is not set to true.
Common situations: Vindex was created without an --owner flag; vschema hand-edited and the owner field dropped; earlier workflow failed before assigning ownership.
Related errors
- one or two tables must be specified
- at least one table must be specified
- vindex is in write-only mode
- no sharded vschema was provided, so you will need to update
- cannot build vschema for keyspace %v: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/99c3da31d6f5990e.
Report an issue: GitHub.