vitessio/vitess · error
schemas are different: %s: %v differs from: %s: %v
Error message
schemas are different: %s: %v differs from: %s: %v
What it means
DiffSchema records this error when both SchemaDefinitions are non-nil but their DatabaseSchema strings (the CREATE DATABASE / default character set portion) differ. It shows the left and right database-level schema side by side.
Source
Thrown at go/vt/mysqlctl/tmutils/schema.go:225
sqlStrings = append(sqlStrings, strings.Join(lines, "\n"))
}
}
return append(sqlStrings, createViewSQL...)
}
// DiffSchema generates a report on what's different between two SchemaDefinitions
// including views, but Vitess internal tables are ignored.
func DiffSchema(leftName string, left *tabletmanagerdatapb.SchemaDefinition, rightName string, right *tabletmanagerdatapb.SchemaDefinition, er concurrency.ErrorRecorder) {
if left == nil && right == nil {
return
}
if left == nil || right == nil {
er.RecordError(fmt.Errorf("schemas are different:\n%s: %v, %s: %v", leftName, left, rightName, right))
return
}
if left.DatabaseSchema != right.DatabaseSchema {
er.RecordError(fmt.Errorf("schemas are different:\n%s: %v\n differs from:\n%s: %v", leftName, left.DatabaseSchema, rightName, right.DatabaseSchema))
}
leftIndex := 0
rightIndex := 0
for leftIndex < len(left.TableDefinitions) && rightIndex < len(right.TableDefinitions) {
// extra table on the left side
if left.TableDefinitions[leftIndex].Name < right.TableDefinitions[rightIndex].Name {
if !schema.IsInternalOperationTableName(left.TableDefinitions[leftIndex].Name) {
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))View on GitHub (pinned to 01a25a7d17)
Solutions
- Run the desired ALTER DATABASE statement on the mismatching tablet's MySQL so both database definitions match
- Re-create the database consistently and re-copy the schema
- Update provisioning tooling to use a single canonical CREATE DATABASE statement
Example fix
// before -- tablet A: CREATE DATABASE vt_app CHARACTER SET utf8 -- tablet B: CREATE DATABASE vt_app CHARACTER SET utf8mb4 // after (on tablet B's MySQL) ALTER DATABASE vt_app CHARACTER SET utf8;
Defensive patterns
Strategy: validation
Validate before calling
leftDb, rightDb := left.GetDatabaseSchema(), right.GetDatabaseSchema()
if leftDb != rightDb {
log.Warn("database schema mismatch before diff", slog.String("left", leftDb), slog.String("right", rightDb))
} Try / catch
er := concurrency.AllErrorRecorder{}
tmutils.DiffSchema("left", left, "right", right, &er)
if er.HasErrors() {
for _, e := range er.Errors { log.Warn("schema diff", slog.Any("error", e)) }
return er.Error()
} Prevention
- Provision all MySQL instances with the same CREATE DATABASE charset/collation template
- Avoid manual ALTER DATABASE on replicas
- Pin the database definition in provisioning/IaC tooling
- Include database-level schema in periodic consistency checks
When it happens
Trigger: DiffSchema invoked on two tablets whose underlying MySQL databases were created with different definitions — e.g. different CREATE DATABASE charset/collation statements.
Common situations: Tablets provisioned at different times with different default charset (utf8 vs utf8mb4); manual ALTER DATABASE on one replica; primary migrated to a new cluster with a different database definition.
Related errors
- schemas are different: %s: %v, %s: %v
- %v has an extra table named %v
- schemas differ on table %v: %s: %v differs from: %s: %v
- permissions differ on %v %v: %s: %v differs from: %s: %v
- SHOW BINARY LOGS returned no rows
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/ebe289545c700900.
Report an issue: GitHub.