Gmail API初始化时报UnicodeDecodeError错误的解决方案咨询
顺着完整堆栈和代码执行顺序排查就能定位:
按照代码逻辑,InstalledAppFlow.from_client_secrets_file读取并解析credentials.json的步骤已经顺利完成(否则根本不会进入run_local_server的执行流程),你之前检查json文件编码的操作完全偏离了问题实际位置。
实际触发报错的环节是run_local_server启动本地授权服务时,底层socket接口解析当前设备全限定域名(FQDN)的过程,也就是堆栈里socket.getfqdn(host)这一步。报错中的0xe9对应非ASCII字符(常见为带重音的外文字符、中文转码后的字节),本质是你的Windows设备主机名、或者本地DNS返回的主机名包含非ASCII字符,Python 3.8的socket模块在解码系统返回的字节串时触发了编码错误。
可直接落地的修复方案
最快的临时修复:给
run_local_server指定固定host参数,绕开自动解析FQDN的逻辑
原来的代码没有传host参数时,库会默认传入空字符串触发主机名全量解析,把对应代码改成:creds = flow.run_local_server(port=0, host="localhost")指定host为
localhost后,授权服务会直接绑定本地回环地址,完全跳过容易触发解码错误的域名解析步骤。根源修复:修改系统主机名去掉非ASCII字符
打开系统「设置」→「系统」→「关于」,选择「重命名这台电脑」,把主机名里的中文、带重音的特殊字符替换为纯英文字符,重启设备后再运行代码。这个方案能从底层解决Python socket对非ASCII主机名的兼容问题,后续跑其他依赖主机名解析的脚本也不会遇到同类报错。无侵入补丁修复:在代码开头拦截解码异常
如果不想改系统设置、也不想修改API调用参数,可以在脚本最开头加一段补丁逻辑,捕获getfqdn的解码错误直接返回本地地址:import socket original_getfqdn = socket.getfqdn def patch_getfqdn(name=""): try: return original_getfqdn(name) except UnicodeDecodeError: return "localhost" socket.getfqdn = patch_getfqdn
注意事项
- 不需要反复调整
credentials.json的编码、甚至重新下载客户端密钥文件,这个文件和当前报错路径完全不相关,改了也解决不了问题。 - 完成授权流程生成
token.pickle文件后,后续脚本运行会直接读取已缓存的授权凭证,不再启动本地授权服务,也就不会再触发这个主机名解析的报错。
内容的提问来源于stack exchange,提问作者Noste

