{"record":{"id":"3e9fb9737aeeebc1","repo":"vitessio/vitess","slug":"this-should-never-happen","errorCode":null,"errorMessage":"This should never happen.","messagePattern":"This should never happen\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/replication/mysql56_gtid_set.go","lineNumber":735,"sourceCode":"\t\t\t\t// this one next round.\n\t\t\t\tif !advanceOther() {\n\t\t\t\t\tbreak diffLoop\n\t\t\t\t}\n\n\t\t\tcase iv.start < otherInterval.start && iv.end > otherInterval.end:\n\t\t\t\t// [1, 7] - [3, 4]\n\t\t\t\t// End is strictly greater. In this case we need to create an extra diff interval. We'll deal with any necessary trimming of it next round.\n\t\t\t\tdiffIntervals[len(diffIntervals)-1].end = otherInterval.start - 1\n\t\t\t\tdiffIntervals = append(diffIntervals, interval{start: otherInterval.end + 1, end: iv.end})\n\n\t\t\t\t// We need to pop s2 at this point. s1's new interval is fully past otherInterval, so no point in comparing\n\t\t\t\t// this one next round.\n\t\t\t\tif !advanceOther() {\n\t\t\t\t\tbreak diffLoop\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tpanic(\"This should never happen.\")\n\t\t\t}\n\t\t}\n\n\t\tif len(intervals) != 0 {\n\t\t\t// If we've gotten to this point, then we have intervals that exist beyond the bounds of any intervals in otherIntervals, and they\n\t\t\t// are all diffs and should be added in whole.\n\t\t\tdiffIntervals = append(diffIntervals, intervals...)\n\t\t}\n\n\t\tif len(diffIntervals) == 0 {\n\t\t\tdelete(differenceSet, sid)\n\t\t} else {\n\t\t\tdifferenceSet[sid] = diffIntervals\n\t\t}\n\t}\n\n\treturn differenceSet\n}","sourceCodeStart":717,"sourceCodeEnd":753,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/replication/mysql56_gtid_set.go#L717-L753","documentation":"Inside Mysql56GTIDSet.Difference, the diff loop switches over a small internal comparison result; the default case is provably unreachable given correct switch arms. panic(\"This should never happen.\") therefore indicates a genuine internal invariant violation — a logic bug or corrupted GTIDSet state, not a caller input problem.","triggerScenarios":"Practically never from valid use; would require a corrupted Mysql56GTIDSet whose internal sort/ordering invariants broke, e.g. intervals constructed manually out of order.","commonSituations":"Custom code constructing mysql56GTIDSet internals directly instead of via ParseGTIDSet; a Vitess bug — report it with the two GTID sets involved.","solutions":["Construct GTID sets only via ParseGTIDSet/ParseGTID, never by populating internal interval structures","If it occurs with stock APIs, file a bug including both GTID sets and their string forms","Re-derive the GTID sets from the servers (SHOW GTIDs / executed_gtid_set) to rule out corrupted in-memory state"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Build sets only via the parser:\nset, err := replication.ParseGTIDSet(\"MySQL56\", raw)\nif err != nil {\n\treturn err\n}","typeGuard":"func isMysql56Set(s replication.GTIDSet) bool {\n\t_, ok := s.(*mysql56GTIDSet)\n\treturn ok\n}","tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\tlog.Error(\"GTIDSet.Difference invariant violation\", slog.Any(\"panic\", r))\n\t}\n}()","preventionTips":["Never populate GTID set internals directly; use ParseGTIDSet","Keep sets sorted/normalized through public APIs","File a bug with both sets if stock APIs ever trigger it"],"tags":["panic","gtid","internal-invariant","gtid-set"],"backgroundTag":"unreachable-invariant-violation","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}