{"record":{"id":"8b4d6ee91af9bb3b","repo":"vitessio/vitess","slug":"bug-invalid-tablettype-forwarded-v","errorCode":null,"errorMessage":"BUG: invalid TabletType forwarded: %v","messagePattern":"BUG: invalid TabletType forwarded: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/throttler/max_replication_lag_module.go","lineNumber":286,"sourceCode":"\tm.lagCache(lagRecord).add(lagRecord)\n\n\tm.lagCache(lagRecord).sortByLag(m.getNSlowestReplicasConfig(lagRecord), m.config.MaxReplicationLagSec+1)\n\n\tm.recalculateRate(lagRecord)\n}\n\nfunc (m *MaxReplicationLagModule) lagCache(lagRecord replicationLagRecord) *replicationLagCache {\n\treturn m.lagCacheByType(lagRecord.Target.TabletType)\n}\n\nfunc (m *MaxReplicationLagModule) lagCacheByType(tabletType topodatapb.TabletType) *replicationLagCache {\n\tswitch tabletType {\n\tcase topodatapb.TabletType_REPLICA:\n\t\treturn m.replicaLagCache\n\tcase topodatapb.TabletType_RDONLY:\n\t\treturn m.rdonlyLagCache\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"BUG: invalid TabletType forwarded: %v\", tabletType))\n\t}\n}\n\nfunc (m *MaxReplicationLagModule) getNSlowestReplicasConfig(lagRecord replicationLagRecord) int {\n\tswitch lagRecord.Target.TabletType {\n\tcase topodatapb.TabletType_REPLICA:\n\t\treturn int(m.config.IgnoreNSlowestReplicas)\n\tcase topodatapb.TabletType_RDONLY:\n\t\treturn int(m.config.IgnoreNSlowestRdonlys)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"BUG: invalid TabletType forwarded: %v\", lagRecord))\n\t}\n}\n\nfunc (m *MaxReplicationLagModule) recalculateRate(lagRecordNow replicationLagRecord) {\n\tif lagRecordNow.isZero() {\n\t\tpanic(\"rate recalculation was triggered with a zero replication lag record\")\n\t}","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/throttler/max_replication_lag_module.go#L268-L304","documentation":"MaxReplicationLagModule.lagCacheByType dispatches to the per-tablet-type lag cache (replica or rdonly). Any other TabletType reaching it is a programming bug, so it panics. Only REPLICA and RDONLY are valid inputs to the throttler's lag bookkeeping.","triggerScenarios":"Calling lagCache / MaxLag / clearReplicaUnderTest with a replicationLagRecord whose Target.TabletType is not REPLICA or RDONLY (e.g. PRIMARY, SPARE, or an unset/UNKNOWN type).","commonSituations":"Feeding the throttler records built from targets that were not filtered to replica/rdonly; protobuf records with TabletType unset (zero value) because the target was never populated; unit tests using PRIMARY targets.","solutions":["Filter replication lag records before feeding the throttler: keep only TabletType_REPLICA and TabletType_RDONLY.","Check that the Target protobuf in lagRecordNow is fully populated (a missing TabletType defaults to UNKNOWN).","If you legitimately need another type, extend lagCacheByType and getNSlowestReplicasConfig with a new cache rather than reusing the existing dispatch."],"exampleFix":"// before\nm.lagCache(lagRecord) // panics for PRIMARY\n// after\nif t := lagRecord.Target.GetTabletType(); t == topodatapb.TabletType_REPLICA || t == topodatapb.TabletType_RDONLY {\n  m.lagCache(lagRecord)\n}","handlingStrategy":"validation","validationCode":"func isReadableTabletType(t topodatapb.TabletType) bool {\n  return t == topodatapb.TabletType_REPLICA || t == topodatapb.TabletType_RDONLY\n}\n// skip records where !isReadableTabletType(lagRecord.Target.GetTabletType())","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter throttler inputs to REPLICA/RDONLY before calling MaxReplicationLagModule","Always populate Target.TabletType when constructing records from protobufs","Remember the zero TabletType is UNKNOWN and will panic — treat it as invalid"],"tags":["go","panic","throttler","tablet-type"],"backgroundTag":"invalid-enum-value","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}