Closed
Labels
Description
Summary
A long-working Web UI session can get stuck for hours with every request failing:
Error from provider (Console Go): Upstream request failed:
[invalid_request_error] The request contains invalid parameters.
Check the request body for any errors or inconsistencies.
while fresh sessions with the same model/variant work fine. The upstream does not disclose WHICH parameter is invalid, opencode's logs do not include the request body, and the server keeps retrying in a ~5s loop ("Failed to drain Session"). The session eventually recovered after hours, surgical message cleanup (removing stale tool providerState / reasoning state, clearing error turns) and a revert to the last working turn — but the actual root cause is not confirmed (see below).
Environment
- opencode version: 0.0.0-beta-17963 / 18286 (reproduced on both)
- OS: Linux 7.0.0-29-generic (Ubuntu) x86_64
- Install/channel: beta
- Server: background service (Web UI), model opencode-go/muse-spark-1.2-contributor#xhigh
Reproduction
- Run a long autonomous session (hours, millions of input tokens, many tool calls and reasoning turns)
- At some point every send starts failing with the upstream
invalid_request_error, persisting for hours - Restarting the server, forking, reverting, and manual message patching alone did not reliably recover it
- The failure behavior was non-deterministic: the same revert boundary + send failed once and succeeded minutes later
Confirmed facts
- Session-specific: fresh sessions with the same model/variant work; all sessions are not affected
- The provider error has no parameter detail, and opencode server logs do not log the outgoing request body → impossible to diagnose which part of the payload the gateway rejects
- The server retries the same invalid request indefinitely (~every 5s, "Failed to drain Session"), creating log spam and keeping the session occupied
- No user-facing recovery path: fork/revert/restart alone did not restore it; the session only recovered after hours + surgical cleanup
- Side finding:
POST /api/session/{id}/forkproduces a session whose messages have no content at all (all parts lost) — likely a separate bug
Verification attempts (what is NOT the cause)
- Injected a real tool
providerState(fc_itemId) part (taken verbatim from the stuck session) into a healthy fresh session → request succeeds. So staleproviderStateitem references alone do not trigger the error. - Stripping reasoning-part state (rs_ itemIds). Patching empty/error assistant turns. Reverting to the last working user message. None of these individually produced stable recovery either.
- Conclusion: root cause is undetermined; the failure looks time-dependent / tied to transient gateway state (e.g., expired encrypted-content or item references, upstream-side limits), possibly worsened by opencode replaying old provider state without validation. This needs the request body + upstream validation detail to pin down.
Expected Behavior
- On upstream
invalid_request_error, opencode should log the outgoing body / per-parameter detail so the invalid field can be identified - Retries should not be infinite for a non-transient 4xx; surface a clear error instead
- A recovery action should exist (e.g., sanitize session history / drop stale provider state), since restart/fork/revert do not work reliably
Suggested fix direction
- Log the outgoing provider request body (DEBUG) including on error
- Stop / back off infinite retry on upstream 4xx invalid-request errors
- Investigate whether replayed
providerStateitem references and encrypted reasoning content should be stripped or refreshed when resuming old/stale turns - Provide a user-facing "repair session" path (strip provider state / truncate to last good turn)
Evidence
Gist (URL-restricted): https://gist.github.com/nico2525nn/80e6860b1f92aa25d0758c50b9086fb2
broken-session-export-sanitized.json— sanitized full session export (incl. the failing error turns)failing-request-reconstructed.json— reconstructed model request for the failing turn (approximation; secrets redacted)log-excerpt.txt— server log lines showing the persistent invalid_request_error / retry loop
Related known issues
- Web UI session-state handling issues (Web UI: opening session URL directly renders blank page (no timeline) #43667 and related) — long sessions tend to break similarly
- [Feature]: add todo support for v2 #42421 — session/state handling background
Activity
github-actions commentedon Aug 27, 2026
This issue might be a duplicate of or closely related to existing issues. Please check:
invalid_request_error+ permanent retry loop pattern, with provider state (thinking blocks) causing the stuck conditionnico2525nn commentedon Aug 27, 2026
Root cause identified upstream — closing this issue in favor of the existing reports and fixes.
Cause (confirmed by related issues)
This is the same class of bug as:
thinkingblock → permanent 400 retry loop": when rebuilding the request history (e.g., after compaction), opencode replays prior assistant reasoning/thinking blocks whosetextcame back empty while the signature / encrypted-content reference (itemId) was preserved. Upstream gateways reject requests where such blocks are not byte-identical to the original →invalid_request_errorwith no field detail → the retry loop rebuilds the same broken payload forever.thinkingblocks (Anthropic extended thinking) #31188 (closed) and Compaction fails:thinking/redacted_thinkingblocks in latest assistant message cannot be modified #41738, DeepSeek compaction can get stuck replaying reasoning/tool history instead of producing a summary #42363 (DeepSeek-flavored replay loop) — same mechanism, including for the DeepSeek/Console-Go family of providers that this report used.Our session's structure matched exactly: reasoning parts with
text: ""plus preservedstate.itemId/ encrypted content references, replayed on every request.Fixes (merged into dev)
Recent merged PRs address this area:
The dev branch's message serialization also now substitutes empty signed reasoning text (
text === "" && hasSignedReasoning ? " " : text), so mutated/empty thinking blocks are no longer sent verbatim.Recommendation
Update to a beta that includes the above fixes rather than relying on manual session surgery (stripping
providerState/reasoning state + revert), which is what was needed to recover the affected session in this report.Closing as resolved upstream (tracked by #39291).