{"record":{"id":"323dd5e730b976ce","repo":"vitessio/vitess","slug":"cannot-decode-position","errorCode":null,"errorMessage":"cannot decode Position","messagePattern":"cannot decode Position","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/replication/replication_status.go","lineNumber":137,"sourceCode":"\t\tSqlState:                               int32(s.SQLState),\n\t\tLastSqlError:                           s.LastSQLError,\n\t\tSslAllowed:                             s.SSLAllowed,\n\t\tHasReplicationFilters:                  s.HasReplicationFilters,\n\t\tAutoPosition:                           s.AutoPosition,\n\t\tUsingGtid:                              s.UsingGTID,\n\t\tSemiSyncPrimaryEnabled:                 s.SemiSyncPrimaryEnabled,\n\t\tSemiSyncReplicaEnabled:                 s.SemiSyncReplicaEnabled,\n\t\tSemiSyncPrimaryStatus:                  s.SemiSyncPrimaryStatus,\n\t\tSemiSyncReplicaStatus:                  s.SemiSyncReplicaStatus,\n\t}\n\treturn replstatuspb\n}\n\n// ProtoToReplicationStatus translates a proto Status, or panics.\nfunc ProtoToReplicationStatus(s *replicationdatapb.Status) ReplicationStatus {\n\tpos, err := DecodePosition(s.Position)\n\tif err != nil {\n\t\tpanic(vterrors.Wrapf(err, \"cannot decode Position\"))\n\t}\n\trelayPos, err := DecodePosition(s.RelayLogPosition)\n\tif err != nil {\n\t\tpanic(vterrors.Wrapf(err, \"cannot decode RelayLogPosition\"))\n\t}\n\tfilePos, err := DecodePosition(s.FilePosition)\n\tif err != nil {\n\t\tpanic(vterrors.Wrapf(err, \"cannot decode FilePosition\"))\n\t}\n\tfileRelayPos, err := DecodePosition(s.RelayLogSourceBinlogEquivalentPosition)\n\tif err != nil {\n\t\tpanic(vterrors.Wrapf(err, \"cannot decode RelayLogSourceBinlogEquivalentPosition\"))\n\t}\n\trelayFilePos, err := DecodePosition(s.RelayLogFilePosition)\n\tif err != nil {\n\t\tpanic(vterrors.Wrapf(err, \"cannot decode RelayLogFilePosition\"))\n\t}\n\tvar sid SID","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/replication/replication_status.go#L119-L155","documentation":"ProtoToReplicationStatus converts a replicationdatapb.Status proto into a ReplicationStatus struct, decoding the Position field via DecodePosition. Because protos arrive over RPC from other Vitess components, it assumes they are valid and panics (wrapped with vterrors) if the Position string cannot be decoded. This indicates a corrupt or foreign-produced proto message.","triggerScenarios":"Calling ProtoToReplicationStatus with a Status whose Position field is empty, truncated, or not a valid GTID set string — e.g. a zero-valued proto, or data written by a component using a different flavor encoding.","commonSituations":"failover/orchestrator code (findErrantGTIDs, FindPositionsOfAllCandidates, ReplicaWasRunning) receiving Status protos from tablets whose Position was never initialized or read from a misconfigured source; version-skew where a peer writes positions differently.","solutions":["Check that the sending tablet's Status.Position is populated and valid before/after RPC (log s.Position when it fails)","Guard the conversion by validating the position string, or use the non-panicking DecodePosition path in new code","Look for version skew or a zero-value Status proto being passed in; fix the producer to send a real position"],"exampleFix":"// before\nstatus := replication.ProtoToReplicationStatus(s)\n// after\nif _, err := replication.DecodePosition(s.Position); err != nil {\n\treturn vterrors.Wrapf(err, \"tablet returned invalid Position %q\", s.Position)\n}\nstatus := replication.ProtoToReplicationStatus(s)","handlingStrategy":"validation","validationCode":"if s == nil || s.Position == \"\" {\n\treturn errors.New(\"Status proto has empty Position\")\n}\nif _, err := replication.DecodePosition(s.Position); err != nil {\n\treturn vterrors.Wrapf(err, \"invalid Position %q\", s.Position)\n}","typeGuard":null,"tryCatchPattern":"func safeProtoToStatus(s *replicationdatapb.Status) (st replication.ReplicationStatus, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"ProtoToReplicationStatus panicked: %v\", r)\n\t\t}\n\t}()\n\treturn replication.ProtoToReplicationStatus(s), nil\n}","preventionTips":["Log the raw proto fields when conversion panics to identify the producing tablet","Validate all position fields after RPC before conversion","Check for version skew between components writing Status protos"],"tags":["panic","replication","proto","position-decode"],"backgroundTag":"invalid-position-in-proto","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}