protoc --decode_raw < payload.bin
# 第 5 个字段若是 0x2a 开头 说明写端仍然是 string
# proto 里补上:reserved 5; reserved "tags";

用户服务的 proto 里删掉了 string tags = 5,半年后新同事加了个 int32 level = 5。发布后老客户端上传的数据在新服务解析,日志里刷 grpc: error unmarshalling request: proto: cannot parse invalid wire-format data,同一个用户每次进页面都失败。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。

追下去是这么回事:字段编号才是二进制报文里的身份,名字和类型都不在字节里。编号被复用到另一种 wire type 之后,读取端按新类型解释旧字节,长度前缀和实际内容对不上,整条消息只能丢弃。

围绕「Protobuf 字段编号复用」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。

处理上按这个顺序:把最近半年删过的字段编号列出来 和 proto 文件里的 reserved 记录对一遍;用 protoc --decode_raw 解一条出问题的报文 看第 5 个字段是长度前缀还是 varint;把复用的编号改回去 在 proto 里补 reserved 5; 防止再被占用;回归时用老版本客户端造一条数据 走一遍新服务。

确认没问题再收工,用老客户端造的报文能被新服务正常解析 日志里不再出现 invalid wire-format data。

作者 9823189