vitessio/vitess · error

%v has an extra view named %v

Error message

%v has an extra view named %v

What it means

Same leftover-tables loop as the extra-table error, but for TableView definitions: a view exists only on the left schema and is reported as 'an extra view named ...'. Unlike extra base tables, internal operation table filtering does NOT apply to views — any unmatched view is reported.

Source

Thrown at go/vt/mysqlctl/tmutils/schema.go:273

		if left.TableDefinitions[leftIndex].Type != right.TableDefinitions[rightIndex].Type {
			if !schema.IsInternalOperationTableName(right.TableDefinitions[rightIndex].Name) {
				er.RecordError(fmt.Errorf("schemas differ on table type for table %v:\n%s: %v\n differs from:\n%s: %v", left.TableDefinitions[leftIndex].Name, leftName, left.TableDefinitions[leftIndex].Type, rightName, right.TableDefinitions[rightIndex].Type))
			}
		}

		leftIndex++
		rightIndex++
	}

	for leftIndex < len(left.TableDefinitions) {
		if left.TableDefinitions[leftIndex].Type == TableBaseTable {
			if !schema.IsInternalOperationTableName(left.TableDefinitions[leftIndex].Name) {
				er.RecordError(fmt.Errorf("%v has an extra table named %v", leftName, left.TableDefinitions[leftIndex].Name))
			}
		}
		if left.TableDefinitions[leftIndex].Type == TableView {
			er.RecordError(fmt.Errorf("%v has an extra view named %v", leftName, left.TableDefinitions[leftIndex].Name))
		}
		leftIndex++
	}
	for rightIndex < len(right.TableDefinitions) {
		if right.TableDefinitions[rightIndex].Type == TableBaseTable {
			if !schema.IsInternalOperationTableName(right.TableDefinitions[rightIndex].Name) {
				er.RecordError(fmt.Errorf("%v has an extra table named %v", rightName, right.TableDefinitions[rightIndex].Name))
			}
		}
		if right.TableDefinitions[rightIndex].Type == TableView {
			er.RecordError(fmt.Errorf("%v has an extra view named %v", rightName, right.TableDefinitions[rightIndex].Name))
		}
		rightIndex++
	}
}

// DiffSchemaToArray diffs two schemas and return the schema diffs if there is any.
func DiffSchemaToArray(leftName string, left *tabletmanagerdatapb.SchemaDefinition, rightName string, right *tabletmanagerdatapb.SchemaDefinition) (result []string) {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Create the missing view on the other side (ApplySchema with the CREATE VIEW statement) or drop it on the side that has it.
  2. Ensure ApplySchema/SchemaReload was run on all tablets in both keyspaces/shards.
  3. Verify with SHOW FULL TABLES on both tablets which side is correct.
  4. Rerun validation to confirm the diff is gone.

Example fix

// before: view only on left
vtctldclient ApplySchema --sql "CREATE VIEW v1 AS SELECT ..." ks
// after: view exists on both sides
Defensive patterns

Strategy: validation

Validate before calling

for _, t := range left.TableDefinitions {
  if t.Type == TableView { found := false; for _, r := range right.TableDefinitions { if r.Name == t.Name { found = true } }; if !found { return fmt.Errorf("missing view %s on right", t.Name) } }
}

Type guard

func isView(td *tmutils.TableDefinition) bool { return td.Type == tmutils.TableView }

Try / catch

err := tmutils.DiffSchema(ctx, left, right)
if err != nil { return fmt.Errorf("view/table set diverged: %w", err) }

Prevention

When it happens

Trigger: Calling DiffSchema where left.TableDefinitions has a TableView entry with no counterpart on the right after the name walk.

Common situations: A view was created on the source keyspace only; a table was converted to a view on one shard; view definitions were excluded from a partial ApplySchema run; backup/restore across versions where views were introduced later.

Related errors


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