问题描述
我目前正在尝试将Ubuntu 14.04盒子升级到Xenial。我正在尝试做发布更新,它失败并出现类似UnicodeDecodeError的错误:’utf-8’编解码器无法解码位置382中的字节0x96:无效的起始字节
看起来像known bug-我已经尝试过了,没有运气找到有问题的软件包,并禁用/删除了我的2个非标准package.lst文件,用于nodesource和veeam存储库。
追溯读取如下内容
Traceback (most recent call last):
File "/tmp/ubuntu-release-upgrader-woadaq_z/xenial", line 8, in <module>
sys.exit(main())
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeMain.py", line 242, in main
if app.run():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1876, in run
return self.fullUpgrade()
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1757, in fullUpgrade
if not self.doPostInitialUpdate():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 943, in doPostInitialUpdate
self.tasks = self.cache.installedTasks
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py", line 806, in installedTasks
for line in pkg._pcache._records.record.split("\n"):
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x96 in position 382: invalid start byte
Error in sys.excepthook:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/problem_report.py", line 416, in add_to_existing
self.write(f)
File "/usr/lib/python3/dist-packages/problem_report.py", line 369, in write
block = f.read(1048576)
File "/usr/lib/python3.4/codecs.py", line 319, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte
Original exception was:
Traceback (most recent call last):
File "/tmp/ubuntu-release-upgrader-woadaq_z/xenial", line 8, in <module>
sys.exit(main())
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeMain.py", line 242, in main
if app.run():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1876, in run
return self.fullUpgrade()
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1757, in fullUpgrade
if not self.doPostInitialUpdate():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 943, in doPostInitialUpdate
self.tasks = self.cache.installedTasks
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py", line 806, in installedTasks
for line in pkg._pcache._records.record.split("\n"):
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x96 in position 382: invalid start byte
=== Command terminated with exit status 1 (Mon Apr 3 09:31:21 2017) ===
日志中没有任何真正有用的东西。我如何获得do-release更新才能工作?
最佳方案
您所拥有的就是升级脚本本身会越过某处的无效数据。您需要查找并删除无效数据。
在这种情况下,它是软件包veeamsnap
。删除该软件包应将其修复。但是,由于每种情况的情况不同,因此我将描述为得出该结论所采取的步骤。这是一个相当复杂的过程。
这很有趣,因为python3字符串都应该使用UTF-8。您在这里(事后发现)是一个C模块(apt_pkg
),以某种方式将非UTF-8数据插入到python3字符串中,因此中断了读取该字符串的所有尝试-注意错误处理程序本身也是如何引发异常的?
我们走进了未知的debugger!
诊断此类问题的最佳方法是使调试器在出现故障的线路之前暂停。使用Python,当您进行一系列这样的嵌套调用时,添加调试器暂停的最简单方法是编辑文件本身。
-
通过您的示例,我们可以看到问题所在的故障位于文件
/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py
行806中,因此让我们启动一个文本编辑器并转到该行。每次运行的临时路径都不相同,因此请确保使用错误输出中的临时路径! -
从这里开始,我们可以通过在错误之前的第806行插入
import pdb; pdb.set_trace();
来首先add a simple pause in the debugger。因为这是Python,所以缩进很重要! -
现在我们需要运行修改后的程序。不要再运行
do-release-upgrade
;可能会下载一个新的。在错误日志中看到“原始异常是”之后的第一行吗?一个与/tmp/ubuntu-release-upgrader-woadaq_z/xenial
?那就是您要运行的那个。因此,以root(或sudo)身份运行该文件。运行该命令将使您进入调试器(pdb): -
从这里,我们计算出总共有多少个软件包。 easy way to do that将运行
sum(1 for _ in self)
。请稍等(这可能需要一段时间),它将打印一个数字。在这个例子中是76028
。现在,由于错误可能不会出现在前几个错误中,并且我们不想手动浏览> 75000程序包,也无法添加异常处理程序(因为错误非常严重,会破坏Python本身),我们需要一种替代方法。 -
删除在步骤4中添加的行。编辑代码以为每个软件包打印出递增编号。例如,在第802行上的循环上方添加
foo = 0
,并在第807行上添加foo += 1; print(foo)
(就在错误行之前)。 -
使用与步骤3中相同的命令再次运行代码。它将打印大量数字。让它继续运行,直到再次打印错误。您可能需要扩大窗口:最后一个数字应该是崩溃的软件包。记下该数字。
-
既然您知道哪个程序包/编号导致崩溃,是时候添加调试器暂停并附带条件,该条件只能在该程序包上执行。例如,如果您在软件包
72285
上崩溃,则在打印foo
的行之后添加if foo == 72285: import pdb; pdb.set_trace()
: -
再次运行代码。现在,当您进入
pdb
时,它应该在引起崩溃的包装上。您可以键入变量pkg
的名称以打印其值,这将告诉您当前包的名称:更一般而言,键入任何变量的名称将打印其输出。 -
删除有问题的程序包,然后从干净的do-release-upgrade重新尝试升级。