无法在ubuntu 14.04上发布更新


27

我目前正在尝试将Ubuntu 14.04盒子升级到Xenial。我正在尝试做发布更新,它失败并出现类似UnicodeDecodeError的错误:'utf-8'编解码器无法解码位置382中的字节0x96:无效的起始字节

似乎是一个已知的错误 -我已经尝试过,并且没有找到令人讨厌的软件包的运气,并且禁用/删除了我的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) ===

日志中没有任何真正有用的东西。我将如何执行发布更新工作?

Answers:


44

您所拥有的就是升级脚本本身会越过某处的无效数据。您需要查找并删除无效数据。

在这种情况下,它就是package veeamsnap。删除该软件包应将其修复。但是,由于每种情况的情况都不相同,因此我将介绍为得出该结论所采取的步骤。这是一个相当复杂的过程。

这是一个有趣的一个,因为python3字符串应该全部是UTF-8。您在这里(事后发现)是一个C模块(apt_pkg),它以某种方式将非UTF-8数据插入到python3字符串中,因此中断了每次读取字符串的尝试-注意错误处理程序本身也是如何引发异常的?

进入未知的 调试器

诊断此类问题的最佳方法是使调试器在出现故障的线路之前暂停。使用Python,当您进行一系列这样的嵌套调用时,添加调试器暂停的最简单方法是编辑文件本身。

  1. 使用您的示例,我们可以看到问题所在的故障在文件/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py行806中,因此让我们启动一个文本编辑器并转到该行。每次运行的临时路径都不相同,因此请确保使用错误输出中的临时路径!

    编辑器的屏幕截图

  2. 从这里开始,我们可以通过在错误之前的第806行插入,首先在调试器中添加一个简单的暂停import pdb; pdb.set_trace();。因为这是Python,所以缩进很重要!

    调试语句的屏幕截图

  3. 现在我们需要运行修改后的程序。不要再跑do-release-upgrade了。可能会下载一个新的。在错误日志中看到“原始异常是”之后的第一行吗?一个带/tmp/ubuntu-release-upgrader-woadaq_z/xenial?那就是您要运行的那个。因此,以root(或sudo)身份运行该文件。

    运行该命令将使您进入调试器(pdb):

    调试器的屏幕截图

  4. 从这里,我们计算出总共有多少个软件包。最简单的方法是运行sum(1 for _ in self)。请稍等(这可能需要一段时间),它将打印一个数字。在这种情况下,它是76028

    现在,由于错误可能不会在前几个错误中发生,并且我们不想手动执行> 75000个程序包,并且我们无法添加异常处理程序(因为错误非常严重,会破坏Python本身) ,我们需要替代方法。

  5. 删除在步骤4中添加的行。编辑代码以为每个软件包打印出递增编号。例如,foo = 0在802行和foo += 1; print(foo)807 行的循环上方添加(就在错误行之前)。

    数字打印代码的屏幕截图

  6. 使用与步骤3中相同的命令再次运行代码。它将打印大量数字。让它继续运行,直到再次打印错误。您可能需要扩大窗口:

    数字输出的屏幕截图

    最后一个数字应该是崩溃的软件包。记下该数字。

  7. 现在,您知道哪个程序包/编号导致崩溃,是时候添加调试器暂停,并且条件是仅在该程序包上执行。例如,如果您在package上崩溃,则在打印行之后72285添加:if foo == 72285: import pdb; pdb.set_trace()foo

    新pdb暂停的屏幕截图

  8. 再次运行代码。现在,当您进入pdb它时,它应该位于会导致崩溃的包装上。您可以键入变量的名称pkg以显示其值,该值将告诉您当前包的名称:

    软件包名称的屏幕截图

    更一般而言,键入任何变量的名称将打印其输出。

  9. 删除有问题的软件包,然后再次尝试升级(从干净的do-release-upgrade开始)。


7
这是gdb的非常好,非常柔和的介绍,几乎所有用户都可以以不同的熟练程度使用它。向我+1,并致以荣誉。而且,顺便说一句,您可能只是添加,在调试器中键入pkg将打印相同名称的变量的值,如第803行所定义。换句话说,pkg不是调试器指令。干杯。
MariusMatutiae

@MariusMatutiae编辑。它是pdb;)(实际上,这实际上更特定于解决此类问题,但是很高兴您可以从总体上容易地理解它。)
Bob

要特别解决此问题,在脚本中添加一行以打印不存在的调试消息想要打印的调试消息的脚本,难道不是很容易吗?(上面有logging.debug消息)或者这是否假设由于该bug可能根本无法打印pkg变量,并且python调试器可以打印任何内容?
CausingUnderflowsEverywhere'Apr

如果我们还有超级用户博客,那么这将是一个很好的补充!
加拿大卢克REINSTATE MONICA '04

@CausingUnderflowsEverywhere从理论上讲,是的。在实践中,链接的错误报告中的类似建议显然没有用(我不确定为什么,只是从OP告诉我的原因),我最终以交互方式进行操作,以防其他原因触发了崩溃-例如,没有知道在这种情况下,record属性本身无法读取。
鲍勃
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.