{"record":{"id":"5f7667a9d14a89f8","repo":"vitessio/vitess","slug":"schemas-are-different-s-v-s-v","errorCode":null,"errorMessage":"schemas are different:\n%s: %v, %s: %v","messagePattern":"schemas are different:\n(.+?): (.+?), (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/mysqlctl/tmutils/schema.go","lineNumber":221,"sourceCode":"\t\t\t\tif strings.HasPrefix(line, \"CREATE TABLE `\") {\n\t\t\t\t\tlines[i] = strings.Replace(line, \"CREATE TABLE `\", \"CREATE TABLE `{{.DatabaseName}}`.`\", 1)\n\t\t\t\t}\n\t\t\t}\n\t\t\tsqlStrings = append(sqlStrings, strings.Join(lines, \"\\n\"))\n\t\t}\n\t}\n\n\treturn append(sqlStrings, createViewSQL...)\n}\n\n// DiffSchema generates a report on what's different between two SchemaDefinitions\n// including views, but Vitess internal tables are ignored.\nfunc DiffSchema(leftName string, left *tabletmanagerdatapb.SchemaDefinition, rightName string, right *tabletmanagerdatapb.SchemaDefinition, er concurrency.ErrorRecorder) {\n\tif left == nil && right == nil {\n\t\treturn\n\t}\n\tif left == nil || right == nil {\n\t\ter.RecordError(fmt.Errorf(\"schemas are different:\\n%s: %v, %s: %v\", leftName, left, rightName, right))\n\t\treturn\n\t}\n\tif left.DatabaseSchema != right.DatabaseSchema {\n\t\ter.RecordError(fmt.Errorf(\"schemas are different:\\n%s: %v\\n differs from:\\n%s: %v\", leftName, left.DatabaseSchema, rightName, right.DatabaseSchema))\n\t}\n\n\tleftIndex := 0\n\trightIndex := 0\n\tfor leftIndex < len(left.TableDefinitions) && rightIndex < len(right.TableDefinitions) {\n\t\t// extra table on the left side\n\t\tif left.TableDefinitions[leftIndex].Name < right.TableDefinitions[rightIndex].Name {\n\t\t\tif !schema.IsInternalOperationTableName(left.TableDefinitions[leftIndex].Name) {\n\t\t\t\ter.RecordError(fmt.Errorf(\"%v has an extra table named %v\", leftName, left.TableDefinitions[leftIndex].Name))\n\t\t\t}\n\t\t\tleftIndex++\n\t\t\tcontinue\n\t\t}\n","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/mysqlctl/tmutils/schema.go#L203-L239","documentation":"DiffSchema compares two SchemaDefinition protos from two tablets. If exactly one side is nil, the comparison cannot proceed and this error records that one tablet reported no schema at all (the two inputs are fundamentally different). Note the message prints the whole proto values, which may be '<nil>'.","triggerScenarios":"DiffSchema(leftName, nil, rightName, right, er) or vice versa — e.g. one vttablet's GetSchema RPC failed or returned an empty response before the diff.","commonSituations":"A tablet is down or unreachable so its schema fetch returned nil; a fresh tablet has not been initialized; the RPC error was swallowed upstream and nil was passed to DiffSchema.","solutions":["Fix the underlying schema fetch on the nil side (check tablet health, re-run GetSchema)","Initialize/restore the empty tablet from a healthy source","Guard the call: only invoke DiffSchema when both SchemaDefinitions are non-nil, and surface the fetch error instead"],"exampleFix":"// before\nleft, _ := getSchema(ctx, tabletA)\ntmutils.DiffSchema(\"a\", left, \"b\", right, er)\n// after\nleft, err := getSchema(ctx, tabletA)\nif err != nil {\n    er.RecordError(fmt.Errorf(\"cannot fetch schema from %s: %v\", \"a\", err))\n    return\n}\ntmutils.DiffSchema(\"a\", left, \"b\", right, er)","handlingStrategy":"type-guard","validationCode":"if left == nil || right == nil {\n    return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, \"cannot diff schema: one side is nil (left=%v right=%v)\", leftName, rightName)\n}","typeGuard":"func bothSchemasPresent(l, r *tabletmanagerdatapb.SchemaDefinition) bool {\n    return l != nil && r != nil\n}","tryCatchPattern":"left, err := getSchema(ctx, leftTablet)\nif err != nil {\n    return vterrors.Wrapf(err, \"cannot fetch schema from %s\", leftName)\n}\ner := concurrency.AllErrorRecorder{}\ntmutils.DiffSchema(leftName, left, rightName, right, &er)\nif er.HasErrors() {\n    return er.Error()\n}","preventionTips":["Check tablet health before running schema diffs","Do not swallow GetSchema errors into nil values","Initialize new tablets fully before including them in diff workflows","Alert on tablets returning empty schema definitions"],"tags":["schema","consistency-check","vitess","mysql"],"backgroundTag":"schema-drift-between-tablets","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}