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
Env vars used without consent + model_not_found causes infinite retry loop #14723
Two distinct but related problems occur when OPENAI_API_KEY is set in the environment and an OpenAI model is selected via /models without running /connect.
1. Design concern — Implicit API key usage
At startup, packages/opencode/src/provider/provider.ts (lines 811–821) scans all environment variables and auto-registers any provider whose key is present, without user confirmation. When the OpenAI provider is registered this way, the background title-generation call in packages/opencode/src/session/summary.ts (summarizeMessage, lines 120–166) resolves gpt-5-nano within the user's own OpenAI provider via Provider.getSmallModel(). As a result, the request is sent directly to OpenAI using the user's API key, consuming their credits without explicit authorization.
Note: When a non-OpenAI provider is in use, title generation goes through OpenCode Zen's own servers by default, as documented in the official provider docs. The concern here is specific to the OpenAI case, where the user's own API key is used silently.
2. Bug — Infinite retry loop on model_not_found
When the selected model is inaccessible, OpenAI returns:
{"type": "error", "error": {"type": "invalid_request_error", "code": "model_not_found", "message": "The model 'gpt-5.3-codex' does not exist or you do not have access to it."}}
In packages/opencode/src/session/retry.ts (lines 92–98), the retryable() function contains an overly broad catch-all condition !!json.error, which matches any response with an error field — including permanent errors like model_not_found. The function returns a non-undefined value, causing packages/opencode/src/session/processor.ts to enter its retry path. The loop (while (true), line 49) has no maximum attempt cap, so the session retries indefinitely until the user manually aborts.
Plugins
No response
OpenCode version
1.2.10
Steps to reproduce
Set a valid OPENAI_API_KEY in your shell environment.
Launch OpenCode TUI.
Select an OpenAI model (e.g., GPT-5.3 Codex) via /models without running /connect.
Type a prompt and submit it.
Observe that the session enters an infinite retry loop displaying "Provider Server Error".
Check API usage; a gpt-5-nano request for session title generation has already fired against your OPENAI_API_KEY.
Thanks for the pointer. #12234 shares the same processor.tswhile (true) loop, but the root cause and fix area are different:
There, StreamIdleTimeoutError is explicitly marked isRetryable: true in message-v2.ts, so retryable() works as intended. The problems are the lack of a max retry cap and the doom loop detection not firing for incomplete tool inputs.
Here, model_not_found is a permanent API-level rejection that is not explicitly marked retryable — it falls into the overly broad !!json.error catch-all in retry.ts lines 92–98 unintentionally. Fixing that issue would not touch this code path.
So the two issues require different fixes: that issue needs a retry cap and better doom loop detection; this one needs retryable() to explicitly exclude invalid_request_error and similar permanent error types.
Additionally, the implicit API key usage described here (Problem 1) is entirely unrelated and should be addressed independently.
Automatically loading the keys is fine, but I would really prefer having a way to remove them to provide a different key or OAuth. (In the desktop app at least).
The desktop app also doesn't really make it clear whether the ChatGPT subscription is being used or not even after logging in, it just says OpenAI [Environment] so I'd assume not.
Activity
github-actions commentedon Feb 22, 2026
This issue might be related to an existing issue. Please check:
processor.tswhile (true)loop andretry.tsinfrastructure, triggered byStreamIdleTimeoutError— same root cause area (overly broad retryable condition), different trigger error type.7shi commentedon Feb 22, 2026
Thanks for the pointer. #12234 shares the same
processor.tswhile (true)loop, but the root cause and fix area are different:StreamIdleTimeoutErroris explicitly markedisRetryable: trueinmessage-v2.ts, soretryable()works as intended. The problems are the lack of a max retry cap and the doom loop detection not firing for incomplete tool inputs.model_not_foundis a permanent API-level rejection that is not explicitly marked retryable — it falls into the overly broad!!json.errorcatch-all inretry.tslines 92–98 unintentionally. Fixing that issue would not touch this code path.So the two issues require different fixes: that issue needs a retry cap and better doom loop detection; this one needs
retryable()to explicitly excludeinvalid_request_errorand similar permanent error types.Additionally, the implicit API key usage described here (Problem 1) is entirely unrelated and should be addressed independently.
Cleroth commentedon Mar 24, 2026
Automatically loading the keys is fine, but I would really prefer having a way to remove them to provide a different key or OAuth. (In the desktop app at least).
The desktop app also doesn't really make it clear whether the ChatGPT subscription is being used or not even after logging in, it just says OpenAI [Environment] so I'd assume not.
github-actions commentedon Jul 4, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.