{"record":{"id":"0e6bf35e4790e254","repo":"vitessio/vitess","slug":"cannot-decode-fileposition","errorCode":null,"errorMessage":"cannot decode FilePosition","messagePattern":"cannot decode FilePosition","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/mysql/replication/replication_status.go","lineNumber":145,"sourceCode":"\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\n\tif s.SourceUuid != \"\" {\n\t\tsid, err = ParseSID(s.SourceUuid)\n\t\tif err != nil {\n\t\t\tpanic(vterrors.Wrapf(err, \"cannot decode SourceUUID\"))\n\t\t}\n\t}\n\treplstatus := ReplicationStatus{\n\t\tPosition:                               pos,","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/replication/replication_status.go#L127-L163","documentation":"ProtoToReplicationStatus decodes the FilePosition field (the binlog file:position as a Position) and panics with a wrapped error if it cannot be decoded. As with the other fields, this fires only when the incoming Status proto contains an invalid FilePosition string.","triggerScenarios":"Calling ProtoToReplicationStatus with a Status whose FilePosition field is malformed — e.g. a legacy/foreign encoding of file-based positions or an empty string from an uninitialized proto.","commonSituations":"Integrations mixing file-based and GTID-based replication status; statuses synthesized by custom tooling writing FilePosition in a non-Position format; version-skewed clusters.","solutions":["Validate s.FilePosition decodes via DecodePosition before conversion","Ensure the producer writes FilePosition using EncodePosition/valid GTID-set syntax","Prefer the non-panicking decode path if you must tolerate legacy statuses"],"exampleFix":"// before\nstatus := replication.ProtoToReplicationStatus(s)\n// after\nif _, err := replication.DecodePosition(s.FilePosition); err != nil {\n\treturn vterrors.Wrapf(err, \"invalid FilePosition %q\", s.FilePosition)\n}\nstatus := replication.ProtoToReplicationStatus(s)","handlingStrategy":"validation","validationCode":"if _, err := replication.DecodePosition(s.FilePosition); err != nil {\n\treturn vterrors.Wrapf(err, \"invalid FilePosition %q\", s.FilePosition)\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\tlog.Warn(\"FilePosition decode panic\", slog.Any(\"panic\", r), slog.String(\"raw\", s.FilePosition))\n\t}\n}()","preventionTips":["Write FilePosition via EncodePosition only","Validate file-based positions when mixing legacy replication with GTID mode","Verify producer tooling writes valid Position strings into Status protos"],"tags":["panic","replication","proto","file-position"],"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"}