1. 译码器初始化失败:从日志定位到配置修复

故障现象与排查思路

译码器进程启动后立即退出,控制台只留下一行 ERROR: decoder init failed (code=2),没有堆栈、没有具体参数名。这类"启动即失败"的问题几乎都发生在初始化阶段:配置加载 → 参数校验 → 资源分配 → 译码图/查表构建。日志与配置文件是唯一可靠的线索来源,排查顺序应当是"先看日志定位阶段,再对照配置定位字段,最后改配置复跑验证"。

运行日志(decoder.log) [INFO] load config: decoder.yaml [INFO] code=distance-3 surface [INFO] decoder=MWPM [INFO] shots=10000 [INFO] max_iter=0 [INFO] validate params... [ERROR] max_iter must be >= 1 [ERROR] init failed (code=2) [INFO] exit ↑ 校验阶段失败,非资源/图构建问题 初始化阶段判定 ① 配置加载 yaml 解析成功 ② 参数校验 范围/类型检查 ③ 资源分配 未到达 ④ 译码图构建 未到达 失败点 decoder.yaml 对照 code: surface_d3 decoder: mwpm shots: 10000 max_iter: 0 seed: 42 max_iter=0 违反约束 max_iter ≥ 1 修复 修复后 max_iter: 1 # 其余字段不变 → 校验通过,进入图构建

从日志读出"失败发生在哪一步"

上面这张图把日志时间线与初始化四阶段对齐,是本次排障的核心判断依据。日志里 validate params... 之后紧跟 max_iter must be >= 1,说明失败发生在参数校验阶段,而不是资源分配或译码图构建。这个判断直接决定了排查范围:只需要检查配置字段的取值,不必去查内存、线程数或探测器坐标。

如果日志停在 build decoding graph... 之后才报错,那才是图构建问题(属于后续案例的范畴)。所以第一步永远是用最后一条 INFO 日志确定阶段边界。

定位到具体字段

错误信息已经点名了字段 max_iter,并给出了约束 >= 1。打开 decoder.yaml 对照,发现该字段被写成了 0。在 MWPM 译码器中,max_iter 表示匹配算法允许的最大迭代/重试次数,取 0 意味着"一次都不允许执行",属于非法值。常见成因是:从模板复制配置时把占位值 0 忘了改,或用脚本批量生成配置时默认值未覆盖。

不要看到 code=2 就去猜错误码含义。不同译码器实现的错误码定义不同,可靠的做法是以日志中的文字描述为准,错误码只作为辅助检索关键字。

修复与验证

把 max_iter 改为合法值(本例取 1,即允许一次匹配),其余字段保持不变,然后重新启动。验证分三层,逐层确认:

  1. 启动层:进程不再立即退出,日志出现 validate params... OK 与 build decoding graph... done。
  2. 功能层:用一小批综合征数据跑一次译码,确认输出逻辑错误率为合理量级(d=3 表面码在低物理错误率下应显著低于 1)。
  3. 回归层:把 max_iter 改回 0 复现一次报错,确认问题根因判断无误,再改回 1。
# 修复前
max_iter: 0

# 修复后
max_iter: 1
建议在配置加载后加一条启动自检:对所有有范围约束的字段做显式断言,并在日志中打印"字段名=值 (约束)"。这样下次同类问题可以在日志里一眼看到是哪个字段越界,而不必再靠错误码反推。

排查要点速查

观察到的日志特征失败阶段优先检查对象
yaml 解析报错 / 文件不存在配置加载文件路径、缩进、字段拼写
validate params 后报字段约束错误参数校验该字段取值与合法范围
资源分配阶段报内存/线程错误资源分配内存上限、并行度设置
build decoding graph 后报错图构建探测器坐标、错误机制映射