IndexError: list index out of range——vLLM LoRA 加载 Qwen3.5 崩溃,choices[0] 的无保护访问

0 阅读1分钟

for i, module in enumerate(target_modules): lora_a_i = lora_a[i] # lora_a 可能比 target_modules 短

✅ 正确:先检查长度

for i, module in enumerate(target_modules): if i >= len(lora_a): logger.warning(f"lora_a has no entry for module {i}, skipping") continue lora_a_i = lora_a[i]


### 场景 2:API 响应 `choices` 为空(LiteLLM#30761)

```python
# ❌ 错误:假设 choices 永远非空
first_choice = response.choices[0]

# ✅ 正确:防御式访问
if not response.choices:
    logger.warning("Empty choices in response, skipping")
    return None
first_choice = response.choices[0]

真实触发条件:上游模型在流式响应的第一个 chunk 中发送 choices=[]——这发生在模型返回空内容、速率限制、或中间件过滤了所有候选时。

场景 3:sys.argv 无保护访问

# ❌ 错误:假设用户传了参数
filename = sys.argv[1]  # python script.py → IndexError

# ✅ 正确
if len(sys.argv) < 2:
    print("Usage: python script.py <filename>")
    sys.exit(1)
filename = sys.argv[1]

场景 4:split() 后取固定下标

# ❌ 错误:假设 split 结果有 3 段
name, version, arch = package_string.split("-")  # "nginx-1.24" → IndexError

# ✅ 正确
parts = package_string.split("-")
if len(parts) == 2:
    name, version = parts
    arch = "amd64"  # 默认值
elif len(parts) == 3:
    name, version, arch = parts

场景 5:迭代中删除元素导致索引漂移

# ❌ 错误:边遍历边删除
items = [1, 2, 3, 4, 5]
for i in range(len(items)):
    if items[i] % 2 == 0:
        del items[i]  # 列表变短,后续 i 越界

# ✅ 正确:列表推导式新建
items = [x for x in items if x % 2 != 0]

排障流程

Step 1:确定哪个列表、哪个下标

Traceback 最后三行:
  File "xxx.py", line N, in func
    xxx[i]
IndexError: list index out of range

→ 列表名:xxx(可能是动态计算的结果)
→ 下标:i(看上一行的赋值或循环变量)
→ 检查 len(xxx) vs i

Step 2:在崩溃点前加防御日志

try:
    value = some_list[index]
except IndexError:
    logger.error(
        f"IndexError: len(some_list)={len(some_list)}, "
        f"index={index}, type={type(index)}"
    )
    raise

Step 3:用 pdbbreakpoint() 停住现场

import pdb; pdb.set_trace()
# 然后:
# (Pdb) len(lora_a)
# (Pdb) i
# (Pdb) type(i)
# (Pdb) lora_a[:10]  # 看前 10 个元素

Step 4:修复原则

模式修复
循环中下标越界if i < len(x):
空列表取首个if x: first = x[0]
split 后段数不够if len(parts) >= N:
API 响应可能为空if response.choices:

总结

层级理解
初级取列表元素时下标超出范围就抛 IndexError
中级CPython 在 PyList_GetItem 中做 O(1) 边界检查,失败时设置 PyExc_IndexError。防御式编程的核心是永远不假设列表非空或下标有效
记忆锚点choices[0] 是无保护下标访问的经典反模式——写 choices[0] 之前,先问自己「如果 choices 是空的,这条代码会怎样?」

同类家族

报错场景本系列篇目
TypeError: 'str' object is not callable变量名覆盖内置函数01
AttributeError: 'NoneType' object has no attributeNone 对象上调用方法02
ImportError: cannot import name循环导入或模块不存在03
KeyError: dict missing key字典键不存在04
RecursionError: max recursion depth递归深度超限05
ModuleNotFoundError: setuptools包安装环境混乱06
JSONDecodeErrorpickle 序列化进程池崩溃07
IndexError: list index out of range无保护下标访问08 ← 本文