{"record":{"id":"c7f4b7db38f0581d","repo":"vitessio/vitess","slug":"bug-cannot-compare-states-v-and-v","errorCode":null,"errorMessage":"BUG: cannot compare states: %v and %v","messagePattern":"BUG: cannot compare states: (.+?) and (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/throttler/max_replication_lag_module.go","lineNumber":441,"sourceCode":"\t\t// timeout.\n\t\treturn true, fmt.Sprintf(\"we didn't see a recent record from it within the last %.1f seconds\", m.config.MaxDurationBetweenIncreases().Seconds())\n\t}\n\n\treturn false, \"\"\n}\n\n// stateGreater returns true if a > b i.e. the state \"a\" is more severe than\n// \"b\". For example, \"decrease\" > \"increase\" returns true.\nfunc stateGreater(a, b state) bool {\n\tswitch a {\n\tcase stateIncreaseRate:\n\t\treturn false\n\tcase stateDecreaseAndGuessRate:\n\t\treturn b == stateIncreaseRate\n\tcase stateEmergency:\n\t\treturn b == stateIncreaseRate || b == stateDecreaseAndGuessRate\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"BUG: cannot compare states: %v and %v\", a, b))\n\t}\n}\n\n// isReplicaUnderTest returns true if a 'replica under test' is currently set\n// and we should not skip the current replica (\"lagRecordNow\").\n// Even if it's the same replica we may skip it and return false because\n// we want to wait longer for the propagation of the current rate change.\nfunc (m *MaxReplicationLagModule) isReplicaUnderTest(r *Result, now time.Time, testedState state, lagRecordNow replicationLagRecord) bool {\n\tif m.replicaUnderTest == nil {\n\t\treturn true\n\t}\n\n\tif m.replicaUnderTest.key != discovery.TabletToMapKey(lagRecordNow.Tablet) {\n\t\tr.Reason = fmt.Sprintf(\"skipping this replica because we're waiting for the next lag record from the 'replica under test': %v\", m.replicaUnderTest.alias)\n\t\treturn false\n\t}\n\n\tif stateGreater(m.replicaUnderTest.state, testedState) {","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/throttler/max_replication_lag_module.go#L423-L459","documentation":"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.","triggerScenarios":"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.","commonSituations":"Same source as error 1708: uninitialized Tester state, corrupted/deserialized enum values, tests constructing states manually with invalid values.","solutions":["Ensure TestedState is always set to a valid enumerated state before any throttler log/replica-under-test logic runs.","Validate state values at Tester construction time so invalid values cannot propagate to stateGreater.","Update the switch in stateGreater if a new state was added to the enum elsewhere but not here."],"exampleFix":"// before\nr := &Tester{}\nstateGreater(r.TestedState, stateIncreaseRate) // panics\n// after\nr := newTesterForTest(... ) // initializes TestedState\nstateGreater(r.TestedState, stateIncreaseRate)","handlingStrategy":"validation","validationCode":"if !validState(a) || !validState(b) {\n  return false // or log and skip the comparison\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Initialize TestedState through the Tester constructor","When adding a new state enum value, update every switch including stateGreater","Cover all state values in unit tests so an unhandled state fails a test, not production"],"tags":["go","panic","throttler","state-machine"],"backgroundTag":"invalid-state-machine-state","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}