解决 TypeError: Descriptors cannot not be created directly 错误
问题描述
当尝试安装或使用 Ray、TensorFlow、Keras 等库时,可能会遇到如下错误:
TypeError: Descriptors cannot not be created directly.
If this call came from a _pb2.py file, your generated code is out of date and must be regenerated with protoc >= 3.19.0.
If you cannot immediately regenerate your protos, some other possible workarounds are:
1. Downgrade the protobuf package to 3.20.x or lower.
2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will use pure-Python parsing and will be much slower).
这个错误通常是由于 Protocol Buffers (protobuf) 包版本不兼容导致的。protobuf 是 Google 开发的用于结构化数据序列化的库,许多机器学习框架和工具都依赖它。
错误原因
错误信息明确指出:当 protobuf 版本过高(特别是从 4.21.0 开始),会导致与之前生成的 Python 协议缓冲区代码不兼容。protobuf 4.x 版本引入了一些重大变更,导致旧代码无法正常工作。
解决方案
解决方案 1:降级 protobuf 版本(推荐)
最常见的解决方案是将 protobuf 降级到兼容版本:
pip install "protobuf<=3.20.1"
或者强制重新安装特定版本:
pip install 'protobuf<=3.20.1' --force-reinstall
也可以使用更宽松的版本约束:
pip install 'protobuf==3.20.*'
TIP
如果项目使用 requirements.txt
文件,添加以下内容到文件末尾以确保覆盖之前的安装:
protobuf==3.20.*
解决方案 2:升级相关依赖
有时,升级依赖库到最新版本可以解决兼容性问题:
# 升级 TensorFlow
pip install tensorflow==2.12.0
# 或者升级其他可能相关的库
pip install wandb --upgrade
pip install streamlit --upgrade
WARNING
请注意,升级主框架(如 TensorFlow)可能会导致其他依赖问题,建议在开发环境中先测试。
解决方案 3:使用环境变量(性能影响)
如果无法立即降级 protobuf,可以使用环境变量作为临时解决方案:
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
性能警告
这种方法会强制使用纯 Python 解析器,而不是更快的 C++ 实现,可能会导致性能显著下降。建议仅作为临时解决方案。
解决方案 4:检查间接依赖
有时 protobuf 可能是通过其他依赖安装的,需要检查并调整间接依赖:
# 查看当前安装的 protobuf 版本
pip show protobuf
# 检查哪些包依赖 protobuf
pipdeptree | grep protobuf
如果有冲突的间接依赖(如 googleapis-common-protos
),可能需要调整其版本或移除它让其他依赖管理 protobuf 版本。
解决方案 5:使用 Conda 管理依赖
如果使用 Conda 环境,可以尝试用 Conda 安装兼容版本:
pip uninstall protobuf
conda install 'protobuf=3.20.1'
各环境下的具体解决方案
# 对于 TensorFlow 2.9+
pip install tensorflow==2.12.0
pip install "protobuf<=3.20.1"
# 对于 TensorFlow 1.x
pip install protobuf==3.15.0
pip install "protobuf<=3.20.1"
pip install streamlit --upgrade
pip install wandb==0.12.17
pip install google-cloud-audit-log==0.2.4
预防措施
- 固定关键依赖版本:在
requirements.txt
或setup.py
中明确指定关键依赖的版本范围 - 使用虚拟环境:为每个项目创建独立的虚拟环境,避免全局包冲突
- 定期更新依赖:定期检查并更新依赖到兼容版本,避免积累过多的版本冲突
总结
TypeError: Descriptors cannot not be created directly
错误通常是由于 protobuf 版本不兼容导致的。最可靠的解决方案是将 protobuf 降级到 3.20.x 或更低版本。如果性能不是主要考虑因素,可以临时设置环境变量作为权宜之计。长期来看,保持依赖库的最新兼容版本是最佳实践。