vitessio/vitess · error
cannot decode RelayLogPosition
Error message
cannot decode RelayLogPosition
What it means
Same family as the Position panic: ProtoToReplicationStatus also decodes the RelayLogPosition field with DecodePosition and panics with a vterrors-wrapped error if it is invalid. The relay log position string in the incoming Status proto is empty or malformed.
Source
Thrown at go/mysql/replication/replication_status.go:141
AutoPosition: s.AutoPosition,
UsingGtid: s.UsingGTID,
SemiSyncPrimaryEnabled: s.SemiSyncPrimaryEnabled,
SemiSyncReplicaEnabled: s.SemiSyncReplicaEnabled,
SemiSyncPrimaryStatus: s.SemiSyncPrimaryStatus,
SemiSyncReplicaStatus: s.SemiSyncReplicaStatus,
}
return replstatuspb
}
// ProtoToReplicationStatus translates a proto Status, or panics.
func ProtoToReplicationStatus(s *replicationdatapb.Status) ReplicationStatus {
pos, err := DecodePosition(s.Position)
if err != nil {
panic(vterrors.Wrapf(err, "cannot decode Position"))
}
relayPos, err := DecodePosition(s.RelayLogPosition)
if err != nil {
panic(vterrors.Wrapf(err, "cannot decode RelayLogPosition"))
}
filePos, err := DecodePosition(s.FilePosition)
if err != nil {
panic(vterrors.Wrapf(err, "cannot decode FilePosition"))
}
fileRelayPos, err := DecodePosition(s.RelayLogSourceBinlogEquivalentPosition)
if err != nil {
panic(vterrors.Wrapf(err, "cannot decode RelayLogSourceBinlogEquivalentPosition"))
}
relayFilePos, err := DecodePosition(s.RelayLogFilePosition)
if err != nil {
panic(vterrors.Wrapf(err, "cannot decode RelayLogFilePosition"))
}
var sid SID
if s.SourceUuid != "" {
sid, err = ParseSID(s.SourceUuid)
if err != nil {
panic(vterrors.Wrapf(err, "cannot decode SourceUUID"))View on GitHub (pinned to 01a25a7d17)
Solutions
- Validate/decode s.RelayLogPosition before calling ProtoToReplicationStatus and treat empty as a valid "no relay log" state if appropriate
- Fix the producer (tablet) so it emits a valid or empty RelayLogPosition
- Check for version skew between components writing the status proto
Example fix
// before
status := replication.ProtoToReplicationStatus(s)
// after
if _, err := replication.DecodePosition(s.RelayLogPosition); err != nil {
return vterrors.Wrapf(err, "invalid RelayLogPosition %q", s.RelayLogPosition)
}
status := replication.ProtoToReplicationStatus(s) Defensive patterns
Strategy: validation
Validate before calling
if _, err := replication.DecodePosition(s.RelayLogPosition); err != nil {
return vterrors.Wrapf(err, "invalid RelayLogPosition %q", s.RelayLogPosition)
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Warn("RelayLogPosition decode panic", slog.Any("panic", r), slog.String("raw", s.RelayLogPosition))
}
}() Prevention
- Treat empty relay-log positions explicitly for replicas that never connected
- Validate RelayLogPosition before ProtoToReplicationStatus in failover paths
- Keep all tablets on compatible Vitess versions
When it happens
Trigger: Calling ProtoToReplicationStatus on a Status proto whose RelayLogPosition is empty/corrupt — common when a tablet has no relay log yet but the field was left as an invalid non-empty string, or a zero proto is converted.
Common situations: Replica status gathering during reparenting where the replica never connected to a primary (no relay log), or peers running mismatched Vitess versions.
Related errors
- cannot decode Position
- cannot decode FilePosition
- err
- cannot decode RelayLogSourceBinlogEquivalentPosition
- cannot decode RelayLogFilePosition
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/c65341ce20cd5dc7.
Report an issue: GitHub.