DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Go 1.27 type switch 报 duplicate case,核对 JSON 类型别名

Go 1.27 的 JSON 类型桥接可使 RawMessage 与实验库 Value 成为同一类型。删除对应重复 case 前,需确认构建条件并在真正报错的依赖源码中修正分支。

升级 Go 1.27 后,原来能编译的 type switch 突然报 duplicate case,而两个 case 使用的是不同包名,可以检查它们是不是已经变成同一个类型的别名。包路径看起来不同,并不能保证类型身份不同。

一个具体组合涉及 github.com/veqryn/slog-json v0.5.0:截断日志字段的代码分别处理标准库 json.RawMessage 与实验 JSON 库的 jsontext.Value。Go 1.27 默认 JSON 路径启用后,实验库相应桥接文件会别名到标准库,而标准 RawMessage 也别名到同一个 Value。两个 case 最终指向同一类型,编译器拒绝重复是正确行为。

容易触发的结构如下:

switch v := value.(type) {
case json.RawMessage:
    // 处理原始 JSON
case experimentjsontext.Value:
    // 处理原始 JSON
}

先查看错误指向的是自己的代码,还是依赖包中的实现,并记录实际模块:

go version
go list -m github.com/veqryn/slog-json github.com/go-json-experiment/json

相关别名文件带构建条件,因此还要保留 GOEXPERIMENT 与工具链信息。不要因为依赖自身的测试能通过,就断言应用端一定使用同一组构建条件和依赖选择。

对明确采用这组别名关系的代码,保留一个 case 即可处理两种写法传入的同一类型,例如:

switch v := value.(type) {
case json.RawMessage:
    if len(v) > limit {
        // 保留原有的超长值处理逻辑
    }
}

这不是把两个类型改成字符串比较,也不是用类型名去猜身份。一个合法 case 已能匹配该别名指向的类型,另一份相同分支不应继续保留。

错误位于依赖的 truncate.go 时,需要采用已核对应改动的依赖版本,或在受控 fork 中修正该实现并固定模块来源。仅修改应用里另一个 switch,不会修掉依赖中的编译错误。不要直接编辑模块缓存文件;重新下载后修改会丢失,也无法稳定进入 CI。

旧工具链或未走桥接条件时,两种类型可能仍独立。需要同时支持那些组合的库,应分别维护符合各构建条件的实现,并验收两条路径,不能无条件删除第二分支后声称旧配置也保留了原行为。这里没有一个“关闭重复 case 检查”的升级修复,关键是代码与当前类型身份一致。

修改后先完整构建原应用,再用标准 RawMessage 与实验 Value 各输入一份短 JSON 和一份超长 JSON,确认截断及输出策略符合原约定。不要只检查编译恢复;长字段若不再受限,日志接收端仍可能拒收。这个诊断针对类型别名合并造成的编译错误,与 JSON 对象因文本编码接口变成字符串是另一条问题。