You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug] litellm ContextWindowExceededError not detected as context overflow #44888
litellm wraps provider context-overflow errors as ContextWindowExceededError: litellm.BadRequestError: Context Window exceeded for given call. No models have context window large enough for this call.
The shared overflow matcher in packages/llm/src/provider-error.ts doesn't recognize the phrase "context window exceeded", so these errors are classified as a generic API error instead of context overflow. This means compaction is never triggered and the session dead-ends.
Plugins
OpenCode version
0.0.0-dev-202608241310
Steps to reproduce
Use a model behind litellm
Set the model max_input_tokens below the serving engines' max contect window, so we see the error from litellm, instead of the error message from the serving engine, being automaticall detected by opencode.
Send enough messages to exceed the litellm context window
Observe the error is treated as a generic API failure rather than triggering automatic compaction
Another live repro with OpenCode v2.0.19 behind a LiteLLM proxy (@ai-sdk/openai-compatible, fronting Azure OpenAI and self-hosted vLLM deployments). It matches the OP's scenario exactly: LiteLLM's max_input_tokens guard fires before the upstream serving engine returns its own (classifiable) overflow error.
Recorded on an assistant message (the raw error also embeds the proxy's fallback list, omitted here):
litellm.ContextWindowExceededError: litellm.BadRequestError: litellm._pre_call_checks: Context Window exceeded for given call. No models have context window large enough for this call.
Model=hosted_vllm/GLM-5.2-AWQ-4bit, Max Input Tokens=300000, Got=300300
model=glm-5.2. context_window_fallbacks=None.
What happens afterwards:
litellm.ContextWindowExceededError is surfaced as a generic API error. No session.compaction.* events result from it, and the documented one-shot recovery ("recover once when a provider rejects a request as too long") never engages. The session is only rescued by a manual /compact.
Long-term data point: across ~3 months of daily use on LiteLLM-backed models I have exactly 10 compaction records — 7 reason: manual, 3 reason: auto (Jul 15, Sep 18, Sep 23). Sessions routinely reach the ceiling and dead-end with these remote 400s until I conclude them by hand; the silent-stop / repeated-error experience described above matches the low auto rate.
Suggestion for the shared matcher (packages/llm/src/provider-error.ts): classify the LiteLLM overflow wrapper too — e.g. normalize "context window exceeded" / ContextWindowExceededError, and/or the very characteristic Max Input Tokens=…, Got=… token pair, into is_overflow. That single phrase would convert dead sessions into automatic compact-and-retry for anyone running models behind LiteLLM.
Related: #46564 (opaque bare 400s not classified — same underlying gap in the matcher), #45168 (auto-compact plateau below the isOverflow threshold).
Happy to provide more data (usage series, clean logs) if useful.
Confirming from another environment (also v2.0.22, macOS arm64, OpenCode via LiteLLM proxy with enable_pre_call_checks: true): the pre-call rejection dead-ends the session exactly as described — litellm.ContextWindowExceededError: litellm.BadRequestError: litellm._pre_call_checks: Context Window exceeded for given call... surfaces as a System Error with no compaction. I filed #56403 with details; closing as a dup of this one is right.
Two artifacts from that investigation that may help review of #54608:
The shipped v2.0.22 classifier list (extracted from the installed binary) confirms none of the current patterns match the litellm router phrasing. The full list, for reference against future litellm message variants:
The contrast case that proves the mechanism: a rejection from the backend (vLLM: This model's maximum context length is 147456 tokens. However, you requested…) matches /maximum context length is \d+ tokens/i and OpenCode logs provider rejected the request as too long; compacting and recovers. Only router-generated rejections (which never reach the backend) fall through.
The pattern in #54608 (/context window exceeded/i) matches the exact string from my logs, so it should close this gap.
Thanks for the clear report. I reproduced this on v2.2.0 and it still happens on the latest dev (a882cf9).
Setup: a mock OpenAI-compatible endpoint stands in for the LiteLLM proxy. It answers the first chat request with HTTP 400 and LiteLLM's exact message (litellm.ContextWindowExceededError: litellm.BadRequestError: litellm._pre_call_checks: Context Window exceeded for given call. ...). Then I ran opencode run against it through @ai-sdk/openai-compatible.
With the LiteLLM message, OpenCode shows it as a plain error and stops. It never sends a compaction request.
With a vLLM-style message (This model's maximum context length is 1000 tokens...), the same setup compacts and retries right away.
So the recovery itself works; LiteLLM's wording just isn't recognized as a context overflow. The script below reproduces it, and CONTROL=1 runs the vLLM comparison. Open PR #54608 proposes adding this pattern. Until a fix lands, running /compact by hand still works.
Related: #56403 (same LiteLLM error, closed as a duplicate of this issue) and #46564 (another kind of overflow error that isn't recognized).
Reproduction script (repro.sh)
#!/usr/bin/env bash# Reproduces #44888: a LiteLLM pre-call "Context Window exceeded" 400 is not# treated as context overflow, so OpenCode never compacts and retries.# Usage: ./repro.sh (uses `opencode` from PATH)# CONTROL=1 ./repro.sh (control: vLLM wording, which IS recognized and compacts)# OC_DEV=/path/to/opencode-checkout ./repro.sh (runs from source)set -u
DIR=$(mktemp -d /tmp/opencode/litellm-XXXX)
PORT=${PORT:-4517}
cat >"$DIR/mock.ts"<<'TS'// Mock LiteLLM proxy: first non-title chat request -> LiteLLM ContextWindowExceededError (400),// all later requests (e.g. compaction / retry) -> a normal streamed reply.let n = 0, chats = 0const msg = process.env.CONTROL ? "This model's maximum context length is 1000 tokens. However, you requested 1300 tokens." : "litellm.ContextWindowExceededError: litellm.BadRequestError: litellm._pre_call_checks: Context Window exceeded for given call. No models have context window large enough for this call.\nModel=hosted_vllm/test, Max Input Tokens=1000, Got=1300\nmodel=test. context_window_fallbacks=None."Bun.serve({ port: Number(process.env.PORT), async fetch(req) { const url = new URL(req.url) if (url.pathname.endsWith("/models")) return Response.json({ data: [{ id: "test", object: "model" }] }) const body = await req.text(); n++ const j = JSON.parse(body); const sys = JSON.stringify(j.messages?.[0]?.content ?? "").slice(0, 90); const last = JSON.stringify(j.messages?.at(-1)?.content ?? "").slice(0, 90) console.log(`REQUEST #${n} bytes=${body.length} tools=${(j.tools ?? []).length} system=${sys} last=${last}`) const isTitle = sys.includes("You name conversations") if (!isTitle) chats++ if (!isTitle && chats === 1) return Response.json({ error: { message: msg, type: null, param: null, code: "400" } }, { status: 400 }) const chunk = (d: any) => `data: ${JSON.stringify({ id: "x", object: "chat.completion.chunk", created: 0, model: "test", choices: [{ index: 0, ...d }] })}\n\n` return new Response(chunk({ delta: { role: "assistant", content: "summary/ok" } }) + chunk({ delta: {}, finish_reason: "stop" }) + "data: [DONE]\n\n", { headers: { "content-type": "text/event-stream" } })} })TS
CONTROL=${CONTROL:-} PORT=$PORT bun "$DIR/mock.ts">"$DIR/mock.log"2>&1&
MOCK=$!; sleep 1
mkdir -p "$DIR/proj";cd"$DIR/proj"
cat > opencode.json <<JSON{ "\$schema": "https://opencode.ai/config.json", "provider": { "litellm": { "npm": "@ai-sdk/openai-compatible", "name": "LiteLLM", "options": { "baseURL": "http://127.0.0.1:$PORT/v1", "apiKey": "x" }, "models": { "test": { "name": "test", "limit": { "context": 200000, "output": 1000 } } } } } }JSONexport HOME="$DIR/home" XDG_CONFIG_HOME="$DIR/home/.config" XDG_DATA_HOME="$DIR/home/.local/share" XDG_STATE_HOME="$DIR/home/.local/state" XDG_CACHE_HOME="$DIR/home/.cache"if [ -n"${OC_DEV:-}" ];thenexport BUN_OPTIONS="--conditions=browser --preload=$OC_DEV/packages/tui/node_modules/@opentui/solid/scripts/preload.js"
OC=(bun --conditions=browser --preload="$OC_DEV/packages/tui/node_modules/@opentui/solid/scripts/preload.js""$OC_DEV/packages/cli/src/index.ts")
else OC=(opencode);fiecho"== version: $("${OC[@]}" --version)"
timeout 120 "${OC[@]}" run --standalone --model litellm/test "hello">"$DIR/run.log"2>&1echo"== exit: $?"echo"== opencode output:"; cat "$DIR/run.log"echo"== mock requests:"; cat "$DIR/mock.log"kill$MOCK
Activity
github-actions commentedon Aug 25, 2026
This issue might be a duplicate of (or closely related to) an existing issue. Please check:
packages/llm/src/provider-error.tsmeans compaction never triggers. That report covers Azure's image-count 400; this one covers litellm'sContextWindowExceededErrorphrasing. The fix would be in the same place, so these may be best addressed together.fabian33-ops commentedon Sep 24, 2026
This is not stale. Please review.
bacigal commentedon Sep 30, 2026
Another live repro with OpenCode v2.0.19 behind a LiteLLM proxy (
@ai-sdk/openai-compatible, fronting Azure OpenAI and self-hosted vLLM deployments). It matches the OP's scenario exactly: LiteLLM'smax_input_tokensguard fires before the upstream serving engine returns its own (classifiable) overflow error.Recorded on an assistant message (the raw error also embeds the proxy's fallback list, omitted here):
What happens afterwards:
litellm.ContextWindowExceededErroris surfaced as a generic API error. Nosession.compaction.*events result from it, and the documented one-shot recovery ("recover once when a provider rejects a request as too long") never engages. The session is only rescued by a manual/compact.reason: manual, 3reason: auto(Jul 15, Sep 18, Sep 23). Sessions routinely reach the ceiling and dead-end with these remote 400s until I conclude them by hand; the silent-stop / repeated-error experience described above matches the low auto rate.Suggestion for the shared matcher (
packages/llm/src/provider-error.ts): classify the LiteLLM overflow wrapper too — e.g. normalize "context window exceeded" /ContextWindowExceededError, and/or the very characteristicMax Input Tokens=…, Got=…token pair, intois_overflow. That single phrase would convert dead sessions into automatic compact-and-retry for anyone running models behind LiteLLM.Related: #46564 (opaque bare 400s not classified — same underlying gap in the matcher), #45168 (auto-compact plateau below the
isOverflowthreshold).Happy to provide more data (usage series, clean logs) if useful.
joryirving commentedon Oct 17, 2026
Confirming from another environment (also v2.0.22, macOS arm64, OpenCode via LiteLLM proxy with
enable_pre_call_checks: true): the pre-call rejection dead-ends the session exactly as described —litellm.ContextWindowExceededError: litellm.BadRequestError: litellm._pre_call_checks: Context Window exceeded for given call...surfaces as a System Error with no compaction. I filed #56403 with details; closing as a dup of this one is right.Two artifacts from that investigation that may help review of #54608:
This model's maximum context length is 147456 tokens. However, you requested…) matches/maximum context length is \d+ tokens/iand OpenCode logsprovider rejected the request as too long; compactingand recovers. Only router-generated rejections (which never reach the backend) fall through.The pattern in #54608 (
/context window exceeded/i) matches the exact string from my logs, so it should close this gap.opencodejr commentedon Oct 28, 2026
Thanks for the clear report. I reproduced this on v2.2.0 and it still happens on the latest
dev(a882cf9).Setup: a mock OpenAI-compatible endpoint stands in for the LiteLLM proxy. It answers the first chat request with HTTP 400 and LiteLLM's exact message (
litellm.ContextWindowExceededError: litellm.BadRequestError: litellm._pre_call_checks: Context Window exceeded for given call. ...). Then I ranopencode runagainst it through@ai-sdk/openai-compatible.This model's maximum context length is 1000 tokens...), the same setup compacts and retries right away.So the recovery itself works; LiteLLM's wording just isn't recognized as a context overflow. The script below reproduces it, and
CONTROL=1runs the vLLM comparison. Open PR #54608 proposes adding this pattern. Until a fix lands, running/compactby hand still works.Related: #56403 (same LiteLLM error, closed as a duplicate of this issue) and #46564 (another kind of overflow error that isn't recognized).
Reproduction script (repro.sh)
Run it:
bash repro.sh