vitessio/vitess · error

BUG: cannot compare states: %v and %v

Error message

BUG: cannot compare states: %v and %v

What it means

stateGreater defines a partial order over the throttler tester states. Comparing a state outside the handled set (or an invalid pair) hits the default branch and panics with both state values embedded. Used by clearReplicaUnderTest/isReplicaUnderTest/showThrottlerLog to rank states.

Source

Thrown at go/vt/throttler/max_replication_lag_module.go:441

		// timeout.
		return true, fmt.Sprintf("we didn't see a recent record from it within the last %.1f seconds", m.config.MaxDurationBetweenIncreases().Seconds())
	}

	return false, ""
}

// stateGreater returns true if a > b i.e. the state "a" is more severe than
// "b". For example, "decrease" > "increase" returns true.
func stateGreater(a, b state) bool {
	switch a {
	case stateIncreaseRate:
		return false
	case stateDecreaseAndGuessRate:
		return b == stateIncreaseRate
	case stateEmergency:
		return b == stateIncreaseRate || b == stateDecreaseAndGuessRate
	default:
		panic(fmt.Sprintf("BUG: cannot compare states: %v and %v", a, b))
	}
}

// isReplicaUnderTest returns true if a 'replica under test' is currently set
// and we should not skip the current replica ("lagRecordNow").
// Even if it's the same replica we may skip it and return false because
// we want to wait longer for the propagation of the current rate change.
func (m *MaxReplicationLagModule) isReplicaUnderTest(r *Result, now time.Time, testedState state, lagRecordNow replicationLagRecord) bool {
	if m.replicaUnderTest == nil {
		return true
	}

	if m.replicaUnderTest.key != discovery.TabletToMapKey(lagRecordNow.Tablet) {
		r.Reason = fmt.Sprintf("skipping this replica because we're waiting for the next lag record from the 'replica under test': %v", m.replicaUnderTest.alias)
		return false
	}

	if stateGreater(m.replicaUnderTest.state, testedState) {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Ensure TestedState is always set to a valid enumerated state before any throttler log/replica-under-test logic runs.
  2. Validate state values at Tester construction time so invalid values cannot propagate to stateGreater.
  3. Update the switch in stateGreater if a new state was added to the enum elsewhere but not here.

Example fix

// before
r := &Tester{}
stateGreater(r.TestedState, stateIncreaseRate) // panics
// after
r := newTesterForTest(... ) // initializes TestedState
stateGreater(r.TestedState, stateIncreaseRate)
Defensive patterns

Strategy: validation

Validate before calling

if !validState(a) || !validState(b) {
  return false // or log and skip the comparison
}

Prevention

When it happens

Trigger: Calling stateGreater(a, b) where a is not one of the enumerated valid states — e.g. a Tester with an uninitialized/invalid TestedState is passed by isReplicaUnderTest or clearReplicaUnderTest.

Common situations: Same source as error 1708: uninitialized Tester state, corrupted/deserialized enum values, tests constructing states manually with invalid values.

Related errors


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