{"record":{"id":"beadfddca924467d","repo":"vitessio/vitess","slug":"schema-diffs-v","errorCode":null,"errorMessage":"schema diffs: %v","messagePattern":"schema diffs: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/wrangler/schema.go","lineNumber":102,"sourceCode":"\taliases, err := wr.ts.FindAllTabletAliasesInShard(ctx, keyspace, shard)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"FindAllTabletAliasesInShard(%v, %v) failed: %v\", keyspace, shard, err)\n\t}\n\n\t// then diff with all replicas\n\ter := concurrency.AllErrorRecorder{}\n\twg := sync.WaitGroup{}\n\tfor _, alias := range aliases {\n\t\tif topoproto.TabletAliasEqual(alias, si.PrimaryAlias) {\n\t\t\tcontinue\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo wr.diffSchema(ctx, primarySchema, si.PrimaryAlias, alias, excludeTables, includeViews, &wg, &er)\n\t}\n\twg.Wait()\n\tif er.HasErrors() {\n\t\treturn fmt.Errorf(\"schema diffs: %v\", er.Error().Error())\n\t}\n\treturn nil\n}\n\n// ValidateSchemaKeyspace will diff the schema from all the tablets in the keyspace.\nfunc (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string, excludeTables []string, includeViews, skipNoPrimary bool, includeVSchema bool) error {\n\tres, err := wr.VtctldServer().ValidateSchemaKeyspace(ctx, &vtctldatapb.ValidateSchemaKeyspaceRequest{\n\t\tKeyspace:       keyspace,\n\t\tExcludeTables:  excludeTables,\n\t\tIncludeViews:   includeViews,\n\t\tIncludeVschema: includeVSchema,\n\t\tSkipNoPrimary:  skipNoPrimary,\n\t})\n\n\tfor _, result := range res.Results {\n\t\twr.Logger().Printf(\"%s\\n\", result)\n\t}\n","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/wrangler/schema.go#L84-L120","documentation":"Aggregate error returned by ValidateSchemaShard when any per-tablet schema diff (or GetSchema error recorded by diffSchema) was recorded in the ErrorRecorder. It wraps all recorded errors, which may include actual schema differences between replicas and the primary as well as schema-fetch failures.","triggerScenarios":"Any tablet in the shard has a schema differing from the primary (different CREATE TABLE definition, missing/extra tables or views), or diffSchema recorded a GetSchema failure for some tablet.","commonSituations":"Manual ALTER TABLE applied to a replica but not replicated (e.g. schema applied outside of vtctldclient ApplySchema with replication broken); restored replica from an older backup; drifted table definitions after a failed migration.","solutions":["Inspect the wrapped error list to see which tables and tablets differ","Re-apply the primary's schema to drifting replicas (vtctldclient ApplySchema --skip-verify or manually syncing the drifted tablets)","Restore replicas from a fresh backup of the primary if drift is extensive","Fix any underlying GetSchema errors first, then re-run ValidateSchemaShard to confirm clean"],"exampleFix":"// before: replica drifted\nmysql> ALTER TABLE customer ADD COLUMN x INT; -- run only on replica\n// after: apply schema through vitess to all tablets\nvtctldclient ApplySchema --sql \"ALTER TABLE customer ADD COLUMN x INT\" commerce","handlingStrategy":"try-catch","validationCode":"// compare table definitions yourself before validating\nprimaryDefs := map[string]string{}\nfor _, t := range primarySchema.TableDefinitions { primaryDefs[t.Name] = t.Schema }\nfor _, t := range replicaSchema.TableDefinitions {\n    if primaryDefs[t.Name] != t.Schema { return fmt.Errorf(\"table %s differs on replica\", t.Name) }\n}","typeGuard":"func schemasMatch(primary, replica *tabletmanagerdatapb.SchemaDefinition) bool {\n    if len(primary.TableDefinitions) != len(replica.TableDefinitions) { return false }\n    for i, td := range primary.TableDefinitions {\n        if td.Name != replica.TableDefinitions[i].Name || td.Schema != replica.TableDefinitions[i].Schema { return false }\n    }\n    return true\n}","tryCatchPattern":"if err := wr.ValidateSchemaShard(ctx, ks, shard, nil, true, false); err != nil {\n    if strings.Contains(err.Error(), \"schema diffs\") {\n        // parse per-tablet diffs from err and re-apply canonical schema\n    }\n}","preventionTips":["Always change schema via vtctldclient ApplySchema, never ad-hoc mysql DDL on replicas","Keep replicas restored from recent primary backups","Run schema validation regularly to catch drift early"],"tags":["vitess","schema-drift","schema-validation"],"backgroundTag":"schema-drift-detected","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}