vitessio/vitess · error

schemas differ on table

Error message

schemas differ on table %v:
%s: %v
 differs from:
%s: %v

What it means

When both tablets have a table with the same name but the CREATE TABLE / view definition string differs, DiffSchema records this error showing each side's table schema. Internal operation tables are skipped. This is the core table-level schema drift detection used by vtctldclient Schema Diff workflows.

Solutions

  1. Apply the correct ALTER TABLE (or CREATE VIEW) on the lagging tablet so the definitions match
  2. Use vtctldclient ApplySchema / controlled replication catch-up to propagate the DDL
  3. Run an online schema change tool across all shards to converge the schema
  4. Re-run the schema diff afterward to confirm zero differences

Example fix

// before
-- tablet A: orders has column `note VARCHAR(100)`
-- tablet B: orders lacks `note`
// after (on tablet B's MySQL)
ALTER TABLE orders ADD COLUMN note VARCHAR(100);
Defensive patterns

Strategy: validation

Validate before calling

for i, lt := range left.TableDefinitions {
    for _, rt := range right.TableDefinitions {
        if lt.Name == rt.Name && lt.Schema != rt.Schema {
            log.Warn("table schema drift", slog.String("table", lt.Name), slog.String("left", lt.Schema), slog.String("right", rt.Schema))
        }
    }
    _ = i
}

Try / catch

er := concurrency.AllErrorRecorder{}
tmutils.DiffSchema("left", left, "right", right, &er)
if er.HasErrors() {
    return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "table schema drift: %w", er.Error())
}
// proceed only when schemas are identical

Prevention

When it happens

Trigger: DiffSchema compares two TableDefinitions with equal names where left.Schema != right.Schema — different columns, indexes, charsets, or view definitions between tablets.

Common situations: A migration/ALTER TABLE was applied on the primary but a replica missed it; schema applied out of order across shards; manual column addition on one tablet; a view redefined on only one side.

Related errors


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

Appendix: source

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

				er.RecordError(fmt.Errorf("%v has an extra table named %v", leftName, left.TableDefinitions[leftIndex].Name))
			}
			leftIndex++
			continue
		}

		// extra table on the right side
		if left.TableDefinitions[leftIndex].Name > right.TableDefinitions[rightIndex].Name {
			if !schema.IsInternalOperationTableName(right.TableDefinitions[rightIndex].Name) {
				er.RecordError(fmt.Errorf("%v has an extra table named %v", rightName, right.TableDefinitions[rightIndex].Name))
			}
			rightIndex++
			continue
		}

		// same name, let's see content
		if left.TableDefinitions[leftIndex].Schema != right.TableDefinitions[rightIndex].Schema {
			if !schema.IsInternalOperationTableName(left.TableDefinitions[leftIndex].Name) {
				er.RecordError(fmt.Errorf("schemas differ on table %v:\n%s: %v\n differs from:\n%s: %v", left.TableDefinitions[leftIndex].Name, leftName, left.TableDefinitions[leftIndex].Schema, rightName, right.TableDefinitions[rightIndex].Schema))
			}
		}

		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))
			}

View on GitHub (pinned to 01a25a7d17)