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

  1. Construct GTID sets only via ParseGTIDSet/ParseGTID, never by populating internal interval structures
  2. If it occurs with stock APIs, file a bug including both GTID sets and their string forms
  3. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/3e9fb9737aeeebc1. Report an issue: GitHub.