ControlNet 预处理阶段抛出 KeyError,通常不是 Stable Diffusion WebUI 主程序损坏,也不是显卡驱动问题,而是模型文件命名没有按照扩展约定的方式保留预处理器关键词。扩展在扫描模型目录时会根据文件名生成索引,若索引键在映射表中不存在,就会在 controlnet_utils.py 或相关 processor 模块中出现 KeyError。这个错误一旦出现,点击生成后会在控制台直接中断,图生图和文生图都会受影响。

错误现象与常见触发场景
出现这个错误时,控制台通常会先打印 ControlNet Preprocessor 相关日志,随后抛出 KeyError。键名可能直接就是缺失的预处理器名称,也可能是从文件名中拆出来的某个错误字段。典型堆栈大致如下:
Traceback (most recent call last):
File 'extensions/sd-webui-controlnet/scripts/controlnet.py', line 1482, in run_annotator
result = preprocessor(input_image, model=model_name)
File 'extensions/sd-webui-controlnet/scripts/utils.py', line 203, in model_dict
model = PREPROCESSOR_DICT[module]
KeyError: 'openpose'
触发场景通常集中在几类:模型从第三方下载站获取后文件名不完整;为了整理方便手动把模型改成 model.pth、control_v1.pth;不同版本模型共用一个目录;更新 ControlNet 扩展后对旧模型的命名解析更严格。还有一种情况是使用整合包时,预置的模型文件名看似正常,实际包含空格或中文,在路径解析时被截断,导致关键词提取失败。
解决前要先确认错误确实来自预处理阶段,而不是出图后的 VAE 或采样器问题。可以查看控制台是否出现 ControlNet Preprocessor 字样,以及 KeyError 后面的单引号中是什么键名。把这个键名和模型实际文件名放在一起对照,基本就能判断是不是命名问题。
KeyError背后的映射机制
ControlNet 的预处理器并不是直接根据模型文件内容判断类型,而是先对文件名做字符串处理。常见做法是把文件名转成小写并按 _ 下划线切分,再检查每个片段是否命中预处理器关键词。比如 control_v11p_sd15_openpose.pth 会先被拆成 control、v11p、sd15、openpose,其中 openpose 命中映射表,最终得到对应的预处理器。
如果文件名是 final_model.pth,拆出来的字段里没有 openpose、depth、canny 等任何一个已注册关键词,有些版本会回退到 none,有些版本则会直接访问字典键,于是报 KeyError。尤其是在 ControlNet 新版对模型名解析逻辑收紧后,文件名中只有版本号或只有作者名的情况容易触发。
下面代码是这类问题的简化演示,真实源码逻辑更复杂,但核心思路相同:
model_name = 'final_model.pth'
segments = model_name.lower().split('_')
processor_key = segments[1] if len(segments) > 1 else 'none'
PREPROCESSOR_DICT = {'openpose': OpenposeDetector, 'depth': MidasDetector}
processor = PREPROCESSOR_DICT[processor_key]
在这个例子里,final_model.pth 拆分后得到的第二个字段是 model.pth,映射表中没有这个键,因此直接触发 KeyError。真实环境中的错误信息会显示 KeyError: 'model.pth' 或 KeyError: 'none',键名不一定是文件全名。把该键名和模型实际文件名对照,就能快速定位到命名环节。
模型文件命名规范检查清单
要避免 KeyError,模型文件建议保持以下结构:control_版本号_sd版本_预处理器_额外标识.pth。核心是文件名中至少出现一个 ControlNet 支持的预处理器关键词。常见关键词包括:
openpose姿态检测depth深度图canny边缘检测softedge柔和边缘scribble涂鸦或线稿seg语义分割lineart线稿normal法线贴图mlsd直线检测shuffle、tile、ip2p、inpaint、recolor
命名时最好使用下划线分隔不同字段,不要使用空格、中文、短横线或仅用数字。比如正确示例:control_v11p_sd15_openpose.pth、control_v11f1p_sd15_depth.pth。错误示例:final.pth、模型1.pth、control v11p sd15 openpose.pth。
实际中不需要强制使用某一套固定命名,只要预处理器关键词完整出现在文件名中即可。若你使用的是已经整合好的模型包,下载后先看文件名,不要因为排序方便而删掉关键词。对于同一种预处理器,如果同时有 fp16 版、pruned 版,可以写成 control_v11p_sd15_openpose_fp16.pth,这样既能区分版本,也不会丢失关键词。
批量检查与修复脚本
模型数量多时,可以用 Python 脚本快速扫描 ControlNet 模型目录,列出所有未命中关键词的文件。将脚本放在 Stable Diffusion WebUI 根目录运行,或者直接修改路径。脚本使用 pathlib 遍历 extensions/sd-webui-controlnet/models 下的 .pth 文件,逐个检查文件名。
from pathlib import Path
ctrl_dir = Path('extensions/sd-webui-controlnet/models')
keywords = ['openpose', 'depth', 'canny', 'softedge', 'scribble', 'seg',
'lineart', 'normal', 'mlsd', 'shuffle', 'tile', 'ip2p',
'inpaint', 'recolor']
for model_path in ctrl_dir.glob('*.pth'):
file_name = model_path.name.lower()
matched = [key for key in keywords if key in file_name]
if matched:
print(f'正常: {model_path.name}')
else:
print(f'异常: {model_path.name} === 未包含标准预处理器关键词')
这段脚本不会修改任何文件,只做检查。输出中带有 异常 的文件名需要重命名。重命名时先退出 WebUI,避免模型正在被占用。建议在文件名中补充对应预处理器名称,例如把 final.pth 改为 control_v11p_sd15_openpose_final.pth,把 model_v1.pth 改为 control_v11p_sd15_depth_v1.pth。修改后重新启动 WebUI,进入 ControlNet 面板刷新模型列表。
如果某些文件来自第三方训练结果,无法确定预处理器类型,可以先从模型说明页或训练参数中找到对应预处理方式,再决定补充哪个关键词。不要把同一个文件复制成多个不同关键词的副本,因为这样虽然可能绕过 KeyError,但会造成模型列表混乱,还容易选错预处理类型。
修复后的验证与预防
重命名完成后,重新打开 Stable Diffusion WebUI,观察控制台启动日志。ControlNet 扩展一般会输出模型加载或预处理器注册信息。看到模型列表中出现新文件名,说明扫描成功。随后用一个简单测试图跑一次该预处理,确认不再报 KeyError。测试时可以只启用一个 ControlNet 单元,分别选择 pose、depth 或 canny,避免多单元相互干扰。
如果重命名后仍报同样的 KeyError,可能是 WebUI 读取了缓存的模型索引。检查扩展目录下是否有临时 Cache 或索引文件,通常在 extensions/sd-webui-controlnet 下,或者删除 WebUI 根目录的 cache.json 后重启。部分整合包会有独立的模型缓存,可先备份再清理。
长期预防建议固定使用模型文件名的规范结构。下载模型时保留原始名称,分类整理放在不同子目录,而不要通过改名去掉关键词。需要区分版本时,在关键词之后追加 fp16、pruned、epoch10 等后缀。这样即使后续 ControlNet 扩展更新解析逻辑,模型文件也能稳定通过预处理映射。
ControlNetSD WebUI模型命名规范修改时间:2026-09-18 22:24:54