DEBUG.WIKI
晚安云;香港 CN2 ¥15/月
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
OnlineSIM:在线接收短信,虚拟号码租用

mypy 检查 Latin-1 源文件,报 stream did not contain valid UTF-8

mypy 原生解析非 UTF-8 源码时可能在类型检查前崩溃。核对编码声明与真实字节,采用 2.4.0 的编码回退实现,临时旧解析还需关闭并行。

带有合法编码声明的 Python 文件,运行时能够解析,mypy 却在 ast_serialize.parse() 中直接抛出 ValueError: stream did not contain valid UTF-8。如果使用了引入原生解析器的开发构建,先核对工具版本与文件原始字节,别把文件另存成 UTF-8 就当成类型问题已经解决。

这条故障曾出现在 mypy 开发提交 0861bb64、Python 3.14.7、Arch Linux 的组合中,输入是带 Latin-1 编码声明的源码。它不是“mypy 2.4.0 不再支持其他编码”的证据:正式 2.4.0 已有解码后重试的处理。

编码声明有效,原生读取仍可能失败

Python 源文件可通过开头两行中的编码声明指定非 UTF-8 编码。声明必须与实际字节一致;把 UTF-8 文件的注释改成 Latin-1,或者反过来只改注释,都不等于转换编码。

受影响路径直接让原生解析器读取文件。底层只接受 UTF-8,尚未按 Python 的编码声明解码,就在类型检查开始前失败了。因此,增加 type: ignore、修改类型注解或清掉普通类型错误,都触不到这个读取环节。

保留出错文件的原始副本,记录实际调用的 mypy 版本、配置、完整栈和解释器。编辑器复制粘贴可能重新编码文件,导致最小样本失去原来的触发条件。

优先采用已有编码回退的正式构建

mypy 2.4.0 的原生解析入口在直接读取抛出 ValueError 后,会重新读取原始字节,按 Python 编码规则解码,再把字符串交给解析器;增量检查使用的哈希仍来自原始字节。

在项目允许的工具环境中,可以选择这份正式实现:

python -m pip install "mypy==2.4.0"
python -m mypy --version
python -m mypy path/to/legacy_module.py

替换最后的路径,保留原配置。若使用锁文件、pre-commit 或编辑器单独的环境,应更新实际执行检查的那一份依赖。这里确认的是读取编码的回退,不保证该版本不存在其他类型检查回归。

旧构建需要临时绕开原生解析时

检查所用构建的帮助,确认确实支持下面两个参数后,才使用串行的旧解析路径:

python -m mypy --num-workers 0 --no-native-parser path/to/legacy_module.py

正式 2.4.0 的参数拼写是 --no-native-parser。非零 worker 数会强制启用原生解析器,因而只添加关闭解析器的选项、同时保留并行配置,可能没有预期效果。环境中的 MYPY_NUM_WORKERS 也可能覆盖配置;对照实际工具环境检查它,而不是只看一行命令。

这条临时路径会放弃并行能力。不要修改安装目录里的解析器代码,也不必为了绕过它改写所有旧文件。

验收应继续使用保留的非 UTF-8 字节和正确编码声明,确认不再出现原生读取崩溃,类型诊断仍正常输出。再放入一处明确的类型不兼容,确认检查器没有跳过整个文件。若报错变成声明未知、实际字节不符或普通语法错误,应处理那项真实输入问题,不能用忽略解码错误来吞掉源码内容。