Bug: context-window-exceeded errors aren't recovered when the provider is self-hosted vLLM #4956
Replies: 2 comments 1 reply
|
Confirmed source-verified against the current tip The dropped The parse site ( providerError = parsed.error
const detail = [providerError?.code, providerError?.type, providerError?.message]
.filter((field): field is string => typeof field === 'string')
.join(' ')That same
Against vLLM's flat body ( One thing that makes the fix trivially safe: the classifier is already ready to fire on vLLM's wording. || /\b(?:maximum|max)(?:\s+(?:allowed|supported))?\s+context\s+(?:length|window)\b/i.test(detail)Your sample message ("This model's maximum context length is 204800 tokens...") matches that branch. So the moment Also confirms a wider pattern: this is the second family member where a provider error body is parsed with a shape assumption (nested-only) that a real backend doesn't honor. (#4922 covers the attachment/TRANSPORT generalization gap.) Worth normalizing the shape at the parse boundary here and treating "flat vs nested WireError" as the rule rather than per-adapter special-casing. Rationale for keeping the nested shape (so I understand the intent): is OpenAI's nested |
|
Added an Agent-first runbook for this boundary: self-hosted vLLM returns flat top-level error JSON, while the rc.2 adapter reads only parsed.error, so CONTEXT_WINDOW_EXCEEDED never reaches compaction-basic. The guide covers sanitized shape capture, normalized-code checks, and adapter tests for flat generic/context errors. https://github.com/sandbaseai/deepseek-harness-handbook/releases/tag/v0.5.388 |
Uh oh!
There was an error while loading. Please reload this page.
Bug: context-window-exceeded errors aren't recovered when the provider is self-hosted vLLM
Environment
dshcommit:b150a55(confirmed unchanged through the currentdsh@0.1.2-alpha.1release tip)llm-deepseekadapter)Symptom
Turn fails outright instead of auto-compacting and retrying:
Happens intermittently — only on this specific error, not on other 400s from the same backend.
Root cause
dshalready has a working recovery path for exactly this case:packages/compaction/compaction-basic/src/index.tslistens foragent/request-error, checksfailure.code === CONTEXT_WINDOW_EXCEEDED_CODE, and if so runs a compaction + retry (bounded bymaxOverflowRetries).That code is only assigned in
packages/llm/llm-deepseek/src/adapter.ts, viahttpErrorCode():detailis built fromproviderError?.code/type/message, andproviderErrorcomes from:WireErrorinpackages/llm/llm-deepseek/src/types.tsonly models the OpenAI-nested shape:vLLM's OpenAI-compatible server does not nest its error body under
"error"— it returns the fields flat at the top level ({"object":"error","message":...,"type":...,"param":...,"code":...}). This is a known, deliberate vLLM behavior — see [vllm-project/vllm#12886](vllm-project/vllm#12886), closed as "not planned," and [vllm-project/vllm#4667](vllm-project/vllm#4667) for the same flat shape in the wild.So against vLLM,
parsed.erroris alwaysundefined,detailis'',isContextWindowExceededError('')isfalse, and every 400 from vLLM gets classified as genericINVALID_REQUEST— including context-length overflows. The existing compaction-and-retry recovery incompaction-basicnever fires, and the raw provider error surfaces to the user instead.Checked
git log b150a55..HEADonadapter.ts,types.ts, anderror.tsinpackages/llm/llm-deepseekandpackages/llm/llm: no relevant changes. The gap is present atb150a55and unchanged at the current release tip.Suggested fix
Accept both shapes when parsing the error body, e.g. in
adapter.ts:and widen
WireErrorintypes.tsto also allow the flat shape (or normalize both into one shape at the parse boundary). Happy to open a PR if that's the preferred direction — wanted to flag the root cause first in case there's a reason the nested-only assumption was intentional.Repro
Point
llm-deepseekat a self-hosted vLLM instance, send a request that exceeds the served model's context window (prompt +max_tokens>--max-model-len), and the 400 will not trigger compaction/retry — it'll surface directly.All reactions