vitessio/vitess · critical

cannot decode RelayLogSourceBinlogEquivalentPosition

Error message

cannot decode RelayLogSourceBinlogEquivalentPosition

What it means

ProtoToReplicationStatus converts a protobuf ReplicationStatus into the in-memory ReplicationStatus struct. Each position field is decoded with DecodePosition, and any decode failure triggers an immediate panic wrapped with the offending field name. This panic means the RelayLogSourceBinlogEquivalentPosition string in the proto is not a valid binlog position (expected 'file:pos' format). It indicates corrupted or hand-mangled status data, since protos are normally produced by ReplicationStatusToProto.

Source

Thrown at go/mysql/replication/replication_status.go:149

}

// 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"))
		}
	}
	replstatus := ReplicationStatus{
		Position:                               pos,
		RelayLogPosition:                       relayPos,
		FilePosition:                           filePos,
		RelayLogSourceBinlogEquivalentPosition: fileRelayPos,
		RelayLogFilePosition:                   relayFilePos,

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Log/inspect s.RelayLogSourceBinlogEquivalentPosition and fix the producer to write valid 'file:position' strings via ReplicationStatusToProto.
  2. Validate the position string with mysql.DecodePosition before calling ProtoToReplicationStatus.
  3. If the field is legitimately unavailable, leave it as empty string only if the consumer treats empty as zero position — otherwise populate it correctly.

Example fix

// before
st := &replicationdatapb.ReplicationStatus{RelayLogSourceBinlogEquivalentPosition: "mysql-bin.000001"}
status := mysql.ProtoToReplicationStatus(st) // panics
// after
st := &replicationdatapb.ReplicationStatus{RelayLogSourceBinlogEquivalentPosition: "mysql-bin.000001:1234"}
if _, err := mysql.DecodePosition(st.RelayLogSourceBinlogEquivalentPosition); err == nil {
    status := mysql.ProtoToReplicationStatus(st)
}
Defensive patterns

Strategy: validation

Validate before calling

if _, err := mysql.DecodePosition(pb.RelayLogSourceBinlogEquivalentPosition); err != nil {
    return fmt.Errorf("invalid RelayLogSourceBinlogEquivalentPosition %q", pb.RelayLogSourceBinlogEquivalentPosition)
}

Try / catch

// Go has no try/catch; isolate the panic:
func safeConvert(pb *replicationdatapb.ReplicationStatus) (st *mysql.ReplicationStatus, err error) {
    defer func() { if r := recover(); r != nil { err = fmt.Errorf("ProtoToReplicationStatus panicked: %v", r) } }()
    s := mysql.ProtoToReplicationStatus(pb)
    return &s, nil
}

Prevention

When it happens

Trigger: Calling ProtoToReplicationStatus (directly or via findErrantGTIDs, FindPositionsOfAllCandidates, ReplicaWasRunning, replicaIOThreadWasRunning) with a proto whose RelayLogSourceBinlogEquivalentPosition is empty-but-nonzero-usage, truncated, or not in 'file:position' format (e.g. 'mysql-bin.000001' without ':123', or negative/garbage position).

Common situations: Manually constructed protobufs in tests or tools, status data round-tripped through external systems that altered the string, or legacy/custom control code writing fields in the wrong format.

Related errors


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