Rust in Everything

常见报错

主线位置:两处。启动时的报错在 KV 池建立之前(参数解析、模型加载、显存测量),对应显存预算;请求时的报错在「模板与分词」之后、进调度之前。本页的原文都取自两个引擎的 Python 代码。打开 Rust 前端(VLLM_USE_RUST_FRONTEND=1 或 SGLANG_RUST_SERVER=1)后,模板、分词和一部分长度检查改由 Rust 做,报错原文可能不同,本页没有逐条核对。

版本:vLLM v0.32.0、SGLang v0.5.22

结论:

  • 启动期的报错大多是一道算术题:权重、激活、KV 加起来超过预算。先看显存预算的公式,再对报错里的数字。
  • 「放不下一个最大长度的请求」,vLLM 在启动时就报;SGLang 不报,而是把单请求上限降到 KV 池大小,等请求来了再拒。
  • 请求期的超长报错,vLLM 在前端渲染时查,SGLang 分两道:分词管理器按上下文长度查,调度器再按 KV 池查。
  • 小标题是源码里的原文片段,{…} 处是运行时填的数字;去掉了这部分,方便按原文搜索。PyTorch 自己的 CUDA OOM 报错不在这两个仓库里,本页不收。
flowchart TB
  subgraph boot["启动"]
    parse["参数解析"] --> load["加载权重、分词器"]
    load --> prof["测显存 / 算比例"]
    prof --> pool["建 KV 池"]
  end
  subgraph req["每个请求"]
    tmpl["聊天模板"] --> tok["分词"]
    tok --> len1["长度检查(前端)"]
    len1 --> len2["长度检查(调度器,SGLang)"]
    len2 --> run["进批、分配 KV"]
  end
  parse -.->|"max_model_len 超过模型配置<br/>预算互相矛盾"| e1["参数报错"]
  load -.->|"分词器加载失败"| e2["分词器报错"]
  prof -.->|"空闲显存不够<br/>权重占满预算"| e3["显存报错"]
  pool -.->|"放不下一个满长请求(vLLM)"| e4["KV 报错"]
  tmpl -.->|"没有模板"| e5["模板报错"]
  len1 -.-> e6["超长报错"]
  len2 -.-> e6
  run -.->|"槽位、KV 分配失败(SGLang)"| e7["运行期 OOM"]

vLLM:启动

is less than desired GPU memory utilization

vllm/v1/worker/utils.py#L761

    if init_snapshot.free_memory < requested_memory:
        raise ValueError(
            f"Free memory on device {init_snapshot.device_} "
            # ...
            f"is less than desired GPU memory utilization "
            f"({cache_config.gpu_memory_utilization}, "
            f"{format_gib(requested_memory)} GiB). Decrease GPU memory "
            f"utilization or reduce GPU memory used by other processes."
        )
  • 触发:启动时的空闲显存小于「总显存 × gpu_memory_utilization」。比例是对总显存算的,所以卡上有别的进程(另一个 vLLM 实例、桌面、残留进程)就会触发。
  • 调:--gpu-memory-utilization 调小到「空闲 / 总量」以下;同一张卡跑两个实例时各给一份,加起来不超过 1。

No available memory for the cache blocks.

vllm/v1/core/kv_cache_utils.py#L1011

  • 触发:预算扣掉权重、其他占用、激活峰值和 CUDA graph 估计之后不剩显存。
  • 调:--gpu-memory-utilization 调大;--max-num-batched-tokens 调小(假前向的 token 数就是它,激活峰值随之变小);权重太大时换量化权重或开张量并行(-tp)。

To serve at least one request with the model's max seq len

vllm/v1/core/kv_cache_utils.py#L1031

        raise ValueError(
            f"To serve at least one request with the model's max seq len "
            f"({max_model_len}), ({format_gib(needed_memory)} GiB KV "
            f"cache is needed, which is larger than the available KV cache "
            f"memory ({format_gib(available_memory)} GiB). {estimated_msg}"
            # ...
  • 触发:KV 池放不下一个 max_model_len 长的请求。max_model_len 默认取模型配置,长上下文模型在小卡上必中:估算下 Llama-3.1-8B 满长 131072 要 16 GiB KV,24 GiB 卡扣掉权重最多剩 7.12 GiB。
  • 报错里的 the estimated maximum model length is … 是二分搜索出的可用长度(estimate_max_model_len)。
  • 调:--max-model-len 设成业务需要的长度或报错给的估计值;或设 -1 让它自动缩;或 --kv-cache-dtype fp8 让每 token 的 KV 减半。

Cannot auto-fit max_model_len: not enough GPU memory available to serve even a single token.

vllm/v1/core/kv_cache_utils.py#L2455

  • 触发:--max-model-len -1 时,连一个 token 的 KV 都放不下。和上面的 No available memory 是同一个原因。
  • 调:同上,先把预算做大或把权重变小。

is greater than the derived max_model_len

vllm/config/model.py#L2646

  • 触发:手设的 --max-model-len 大于模型配置推出的长度(max_position_embeddings 等字段,乘上 RoPE 缩放系数,再和分词器的 model_max_length 取小)。
  • 调:改小;确有把握时设 VLLM_ALLOW_LONG_MAX_MODEL_LEN=1。报错原文同时警告:用 RoPE 的模型超出后会得到 nan。

smaller than max_model_len

vllm/config/scheduler.py#L321

  • 触发:关了分块预填充(--no-enable-chunked-prefill),又手设了比 max_model_len 小的 --max-num-batched-tokens。不分块时一个 prompt 必须一步算完,预算小于最大长度就意味着长请求永远进不来。
  • 调:二选一:打开分块预填充,或把 --max-num-batched-tokens 设到不小于 --max-model-len。没手设预算时 vLLM 会自动抬(arg_utils.py#L3141),不会报这条。
  • 同一函数里还有一条:max_num_batched_tokens 不能小于 max_num_seqs(#L329)。

Error in memory profiling.

vllm/v1/worker/gpu_worker.py#L719

  • 触发:测显存期间,同一张卡上别的进程释放了显存,测得的「消耗」成了负数。原文建议把 vLLM 放进独立容器。
  • 注意它是 assert,Python 带 -O 运行时这道检查不存在,测量会悄悄出错。

Failed to load the tokenizer. If the tokenizer is a custom tokenizer not yet available in the HuggingFace transformers library

vllm/tokenizers/hf.py#L198

  • 触发:分词器类在当前 transformers 里不存在,或者要执行仓库里的分词器代码,而没开 trust_remote_code。
  • 调:确认模型仓库可信后加 --trust-remote-code(默认 False);或按原文提示升级 transformers。

vLLM:请求

This model's maximum context length is

vllm/renderers/params.py#L528

        if len(tokens) > max_input_tokens:
            # ...
            raise VLLMValidationError(
                f"This model's maximum context length is "
                f"{self.max_total_tokens} tokens. However, your prompt "
                f"contains {qualifier}{token_count} input tokens, which "
                f"exceeds this limit even without any output tokens. "
                # ...
  • 触发:分词后的 prompt 长度超过输入上限(由 max_model_len 决定)。分词前还有一道按字符数的粗查,文本超过「输入上限 × 分词器每 token 最多字符数」直接拒,原文开头相同(#L389)。
  • 调:服务端调大 --max-model-len(受 KV 池限制,见上一节);客户端缩短输入,或在请求里传 truncate_prompt_tokens。

longer than the maximum model length of

vllm/v1/engine/input_processor.py#L589

  • 触发:进引擎前的第二道检查。prompt 长度大于 max_model_len;等于时也报,因为至少要留一个输出 token(#L593)。多模态模型的提示里会说明图像 token 也算在内。
  • 调:同上。

Please request fewer output tokens.

vllm/renderers/params.py#L265

  • 触发:请求里的 max_tokens(或 max_completion_tokens)大于模型的总长度上限。
  • 调:客户端调小。客户端不传 max_tokens 时,vLLM 用「max_model_len − 输入长度」作为上限(api_utils.py#L169),不会触发这条。

As of transformers v4.44, default chat template is no longer allowed, so you must provide a chat template if the tokenizer does not define one.

vllm/renderers/hf.py#L797

  • 触发:调 /v1/chat/completions,而模型没有聊天模板:启动参数没给,处理器和分词器里都没有,vLLM 内置的兜底模板也没有这个模型(查找顺序见 resolve_chat_template)。常见于基座模型。
  • 调:--chat-template 给一个模板文件;或者改用 /v1/completions,自己拼 prompt。

SGLang:启动

Loaded weights leave no GPU memory for the KV cache under

python/sglang/srt/mem_cache/kv_cache_configurator.py#L2732

            raise ValueError(
                f"Loaded weights leave no GPU memory for the KV cache under "
                f"--mem-fraction-static={get_schedule().mem_fraction_static}. "
                f"Raise --mem-fraction-static above "
                f"{suggested_mem_fraction_static:.3f} "
                # ...
  • 触发:加载完权重(开了投机解码时包括草稿模型)后,空闲显存已经小于「加载前空闲 × (1 − mem_fraction_static)」。也就是权重本身超过了静态比例。
  • 调:按原文给的最小值调大 --mem-fraction-static,再留些 KV 的余量;或换量化权重、开 --tp-size。默认比例在小卡上偏低(24 GiB 卡约 0.704),8B bf16 模型只剩约 1.9 GiB 给 KV(估算),更大的模型在这张卡上会直接撞到这条。

Not enough memory. Please try to increase --mem-fraction-static.

python/sglang/srt/model_executor/pool_configurator.py#L93

  • 触发:算出的 KV 池 token 数不大于 0。和上一条同源,走的是另一条代码路径(比如各池扣掉固定开销之后)。
  • 调:同上。

Failed to load the tokenizer. If the tokenizer is a custom tokenizer not yet available in the HuggingFace transformers library

python/sglang/srt/utils/hf_transformers/tokenizer.py#L203

  • 触发、调法和 vLLM 那条相同:--trust-remote-code(默认 False)。同一函数里另一条 Failed to load the tokenizer. If you are using a LLaMA V1 model 针对 LLaMA V1 的慢速分词器(#L184)。

No chat template found, defaulting to 'string' content format

python/sglang/srt/parser/template_manager.py#L181

  • 这是一条 info 日志,不是报错:SGLang 在启动时发现分词器没有聊天模板,不拦。之后的 /v1/chat/completions 请求会在 transformers 套模板时失败,那条报错的原文在 transformers 里,不在 SGLang 仓库。
  • 调:--chat-template。看到这行日志就该补,不必等到请求失败。

SGLang:请求

is longer than the model's context length

python/sglang/srt/managers/tokenizer_manager.py#L1354

  • 触发:分词后的输入长度(加上保留 token)不小于 context_len。context_len 默认取模型配置,--context-length 可改。
  • 调:--allow-auto-truncate 打开后不报错,截掉超出的部分并打 warning(#L1346)。默认关。

Requested token count exceeds the model's maximum context length

python/sglang/srt/managers/tokenizer_manager.py#L1377

  • 触发:输入加请求的 max_new_tokens 超过 context_len。只在客户端传了输出上限时检查。
  • 调:客户端调小输出上限;--allow-auto-truncate 时改为把 max_new_tokens 截到剩余长度。

exceeds the maximum allowed length

python/sglang/srt/managers/utils.py#L278

            error_msg = (
                f"Input length ({len(req.origin_input_ids)} tokens) exceeds "
                f"the maximum allowed length ({max_req_input_len} tokens). "
                f"Use a shorter input or enable --allow-auto-truncate."
            )
  • 触发:调度器收请求时的第二道检查(scheduler.py#L3119)。上限 max_req_input_len = min(context_len, KV 池 token 数) − 6(tp_worker.py#L549)。所以输入比上下文长度短、却比 KV 池长时,过得了上一条,过不了这一条。这是 vLLM 在启动时就报的那类问题,SGLang 推到了请求时。
  • 调:让 KV 池更大(--mem-fraction-static、更小的 --chunked-prefill-size、--kv-cache-dtype);或 --allow-auto-truncate。

Request prompt exceeds the KV memory budget

python/sglang/srt/managers/scheduler.py#L2624

  • 触发:给请求定输出上限时,KV 分配器算出「输入本身就放不下」(考虑页对齐、滑动窗口、分块大小),请求直接以 abort 结束。
  • 调:同上一条,让 KV 池更大或缩短输入。

SGLang:运行期

alloc_req_slots runs out of memory.

python/sglang/srt/mem_cache/allocation.py#L338

  • 触发:请求槽位池(req_to_token,行数就是 max_running_requests)分不出位置。
  • 调:原文建议调小 --max-running-requests。

Prefill out of memory. Try to lower your batch size. / Decode out of memory. Try to lower your batch size.

allocation.py#L232、#L606

  • 触发:给预填充或解码分配 KV 槽位时,驱逐前缀树之后仍不够。正常情况下调度器收请求时的预算和解码前的 retract(见抢占)会先挡住,走到这里说明预估失准。报错后会打印前缀树。
  • 调:原文建议减小批,即调小 --max-running-requests;也可以调大 --schedule-conservativeness 让收请求更保守。哪种负载下会走到这里,待实测(C3-2)。

小结

  • vLLM 启动:空闲显存不够预算(调低比例)、预算扣完不剩(调高比例或减小每步 token)、KV 放不下一个满长请求(调小 --max-model-len 或设 -1)、--max-model-len 超过模型配置、关分块时预算小于最大长度。
  • vLLM 请求:输入超过 max_model_len(两道检查)、输出上限超过总长度、没有聊天模板(--chat-template)。
  • SGLang 启动:权重超过静态比例(调大 --mem-fraction-static)。KV 池小于上下文长度不报错,到请求时以 exceeds the maximum allowed length 拒掉。没有聊天模板只打一行 info。
  • 两边分词器加载失败都指向 --trust-remote-code。
  • 打开 Rust 前端后,请求侧的部分报错原文会变,本页未核对。

💬 关联讨论

发起讨论
加载中...