vitessio/vitess · error
This should never happen.
Error message
This should never happen.
What it means
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.
Source
Thrown at go/mysql/replication/mysql56_gtid_set.go:735
// this one next round.
if !advanceOther() {
break diffLoop
}
case iv.start < otherInterval.start && iv.end > otherInterval.end:
// [1, 7] - [3, 4]
// 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.
diffIntervals[len(diffIntervals)-1].end = otherInterval.start - 1
diffIntervals = append(diffIntervals, interval{start: otherInterval.end + 1, end: iv.end})
// We need to pop s2 at this point. s1's new interval is fully past otherInterval, so no point in comparing
// this one next round.
if !advanceOther() {
break diffLoop
}
default:
panic("This should never happen.")
}
}
if len(intervals) != 0 {
// If we've gotten to this point, then we have intervals that exist beyond the bounds of any intervals in otherIntervals, and they
// are all diffs and should be added in whole.
diffIntervals = append(diffIntervals, intervals...)
}
if len(diffIntervals) == 0 {
delete(differenceSet, sid)
} else {
differenceSet[sid] = diffIntervals
}
}
return differenceSet
}View on GitHub (pinned to 01a25a7d17)
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
Defensive patterns
Strategy: type-guard
Validate before calling
// Build sets only via the parser:
set, err := replication.ParseGTIDSet("MySQL56", raw)
if err != nil {
return err
} Type guard
func isMysql56Set(s replication.GTIDSet) bool {
_, ok := s.(*mysql56GTIDSet)
return ok
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Error("GTIDSet.Difference invariant violation", slog.Any("panic", r))
}
}() Prevention
- 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
When it happens
Trigger: Practically never from valid use; would require a corrupted Mysql56GTIDSet whose internal sort/ordering invariants broke, e.g. intervals constructed manually out of order.
Common situations: Custom code constructing mysql56GTIDSet internals directly instead of via ParseGTIDSet; a Vitess bug — report it with the two GTID sets involved.
Related errors
- unreachable
- panic(err)
- err
- The receiver ReplicationStatus contained a Mysql56GTIDSet in
- bad unsigned integer type
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/3e9fb9737aeeebc1.
Report an issue: GitHub.