#9482·pi

Empty-body 400 from OpenAI-compatible gateways (opencode-go/deepseek-v4-flash) misclassified as context overflow → destructive auto-compaction destroys up to ~400k tokens

Author: acidnikCreated Sep 11, 2026Updated Sep 17, 2026

Severity

This is a serious, non-cosmetic bug that directly degrades pi's quality of work. A transient HTTP 400 with an empty body from an OpenAI-compatible gateway is misclassified as context overflow, which makes pi skip retry and destroys up to ~400k tokens of conversation history via auto-compaction — even though context usage is only 13–40% of the model's window and the error message carries zero context/token semantics. Sessions lose exact constraints, file paths, decisions, and in-progress work, forcing the model to continue from a summary.

Summary

isContextOverflow() classifies 400 status code (no body) as context overflow via the generic Cerebras regex:

/^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i, // Cerebras: 400/413 with no body

This pattern was written for Cerebras backends (which genuinely report overflow as empty-body 400/413), but it matches any OpenAI-compatible gateway that returns an empty-body 400. On the built-in opencode-go provider (DeepSeek V4 Flash) the gateway intermittently returns exactly such a response. Result: zero retry + destructive overflow auto-compaction (_runAutoCompaction("overflow")).

Environment

  • pi 0.84.4 (also reproduced by user @ShoichiTect on 0.85.1 in #8682)
  • api=openai-completions, provider=opencode-go (baseUrl https://opencode.ai/zen/go/v1), model=deepseek-v4-flash, contextWindow = 1,000,000, maxTokens = 384,000
  • No custom compaction settings → defaults apply: reserveTokens = 16,384 → real threshold = 983,616 tokens

Evidence (from a session log)

Two occurrences in one session, provider opencode-go / deepseek-v4-flash:

t preceding request usage (input + cacheRead) compaction tokensBefore
2026-09-11T10:19:01Z error 396,823 397,619
2026-09-11T10:26:49Z error 126,294 127,210
  • Both compactions are immediately preceded by an assistant message with stopReason: "error", errorMessage: "400 status code (no body)", and all-zero usage (the request was rejected before any usage was computed).
  • Real overflow threshold is 983,616; the failing requests were at ~40% and ~13% of the 1M window. Neither was anywhere near overflow.
  • The 400 fires at wildly different sizes (≈397k and ≈127k) — not a genuine token-limit rejection. Requests of the same size succeeded dozens of times before/after in the same session.
  • The OpenAI SDK surfaces the message because the response body is empty: openai/core/error.mjs makeMessage()status && !msg → "${status} status code (no body)". Nothing about context is in the text.

Why this is a real bug

  1. An error whose message contains no context/token wording must never land on the terminal overflow path. The classification rests solely on the Cerebras regex matching by accident.
  2. Inconsistent error handling: the same gateway's empty-body 429/5xx map to retryable transient errors (backoff, retry) — but empty-body 400/413 take the zero-retry destructive compaction path. A transient gateway glitch should be retried, not compacted.
  3. Impact is severe: losing 100–400k tokens mid-task breaks pi's constraints, file paths, partial work, and cross-turn coherence — i.e. it materially degrades the quality of affected sessions.

Proposed fix

  1. Gate the bodyless pattern on provider === "cerebras" (as suggested in #8682), or remove bodyless 400 from OVERFLOW_PATTERNS entirely — keep bodyless 413 gated to Cerebras (mirrors openclaw/openclaw#119596 which removed only the 400).
  2. Add empty-body 4xx to RETRYABLE_PROVIDER_ERROR_PATTERN so transient gateway 400s get bounded backoff retry instead of compaction (consistent with 429/5xx handling).

Related

  • #8682 — same issue, auto-closed by the bot before maintainer review despite a reproduction + fix proposal on 0.85.1 (compaction tokensBefore 41,682 / 108,534 / 157,310 at threshold 983,616).
  • #8526 — false overflow from the same Cerebras regex for Vertex AI.
  • #5763 — gateway error bodies are swallowed in general (root cause of opaque "(no body)" strings).
  • deepseek-ai/deepseek-harness discussion #2865 — same mislabeling for other non-Cerebras OpenAI-compatible providers.
  • openclaw/openclaw#119596 — analogous fix (removed bodyless 400 from overflow patterns).

This is reproducible with the stock opencode-go provider and an OpenCode Go key — no custom provider or config needed.