Repository navigation
Description
Summary
Automatic session-title generation silently fails for sessions whose primary model is any free opencode/* model (e.g. opencode/glm-5.3-flash-free, opencode/deepseek-v4.1-flash-free). The session title stays empty forever and the TUI renders it as “New session — ”. There is no log line, no retry, and no fallback (e.g. to the first user message), so the failure is completely invisible — to the user and to debugging.
Environment
- opencode version: 2.1.3 (latest channel, Homebrew
opencode-v2) - OS: Darwin 27.0.0 arm64 (macOS)
- Terminal: VS Code integrated terminal (
TERM_PROGRAM=vscode,xterm-256color, truecolor) - Shell: /bin/zsh
- Install/channel: latest
- Active plugins: none (verified in global config)
Reproduction
-
Run a session whose primary model is a free opencode-zen model, without
--title:opencode run -m opencode/glm-5.3-flash-free "Reply with two characters: OK" -
Wait for the reply to finish, then wait 30+ seconds.
-
Check the session title (TUI session list, or
GET /api/session):titleis null/undefined — the TUI shows “New session — ”.
Results from 5 identical runs (same machine, same day, default log level) — reproducible consistently:
| arm | runs | title after turn |
|---|---|---|
opencode/glm-5.3-flash-free |
3 | null — untitled forever |
opencode/deepseek-v4.1-flash-free |
1 | null — untitled forever |
custom Gemini provider via local proxy, gemini-3.5-flash-lite (control) |
1 | auto-generated (“Short reply request”) |
Also observed on ordinary TUI sessions opened with the default free model — every such session that day ended untitled, which is what surfaced this bug.
Additional observations:
- Not a timing problem: still untitled at t+30s and minutes later.
- The title LLM call persists no message record in either the failing or the successful arm, so nothing is observable session-side.
- Default-level service logs contain zero lines about title generation in either arm.
Expected Behavior
- If title generation fails, fall back — e.g. use the (truncated) first user message as the title — and/or retry.
packages/core/test/session-title.test.tsalready anticipates fallback (“falls back to the primary model when the small model fails”, “uses the primary model at its lowest variant without a small model”). - Emit at least a warning log with provider/model and the upstream error, so failures are diagnosable.
Actual Behavior
Silent no-op: the LLM attempt failure is swallowed, nothing is logged, and the session remains untitled forever.
Additional Context
Source reading on dev (paths relative to repo root):
-
packages/core/src/session/runner/llm.ts(~L171): once the first user message is promoted,title.generate(sessionID)is started as a bareFiberMapfiber (onlyIfMissing: true) with no failure observer. In-file comment: “Title generation starts once input is visible and must not delay model execution.” — the title call runs concurrently with the first assistant turn. -
packages/core/src/session/title.ts— every failure path returns silently:if (LLMEvent.is.providerError(event)) failed = true ... Effect.catchTag("AI.Error", () => Effect.sync(() => { failed = true })) ... if (failed) return // attempt() → undefined ... if (!title) return // generate() → silent exit
The module contains no logging at all.
-
packages/core/src/model.ts—Model.small(providerID)only matches a hardcoded family list (gpt-luna,gemini-flash-lite,gemini-flash,claude-haiku). The opencode free catalog (glm-5.3-flash-free,deepseek-v4.1-flash-free,big-pickle,muse-spark-1.3-contributor-free, …) matches none, so selection falls through to the primary model itself — i.e. the very model already serving the first turn. On free models with tight concurrency, this extra concurrent request is the most plausible trigger for the hidden upstream error (unverified — no error surfaces anywhere to confirm it).
Probable impact: everyone running free opencode/* models (these are the provider's preferred defaults, see PREFERRED_FREE in model.ts) accumulates permanently untitled sessions.
Related but distinct open issues: #52004 (small-model selection prefers a metered model), #54185 (title agent produces conversational replies), #54401 (title request has no output limit). None of them cover the silent-failure / permanently-untitled symptom.
Suggested fixes (any of):
- log a warning including provider/model and the upstream error whenever a title attempt fails;
- schedule the title call after the first turn settles, or retry on later turns (the
isUntitledre-check already exists); - fall back to the truncated first user message as the title when generation fails.
Activity
opencode-agent commentedon Oct 23, 2026
Thanks for the detailed write-up. I think this is a duplicate of #58176. Both are on 2.1.3 with free
opencode/*models, sessions stay untitled, and the failure is never logged. #58176 has been reproduced. The title request is sent automatically, but the free tier rejects it with403 FreeTierError("OpenCode's free tier can only be used from within OpenCode"), andSessionTitle.attemptthen drops the error without logging it. So the cause looks like the request shape, not the concurrent first turn.Possible duplicates and related issues, most likely first:
opencode/*models, titles never generated, failure not logged (reproduced, root cause identified)Model.smallpicks a metered model even when a free one existsThe bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different. Any extra details are welcome on #58176.
xhugoliu commentedon Oct 23, 2026
Agreed — the free-tier-gate root cause identified in #58176 fits my data better than my own write-up did. The control arm in my matrix (custom local-proxy Gemini provider,
gemini-3.5-flash-lite) auto-titled successfully while running concurrently with the first turn, which rules out my initial "title call races the first turn / free concurrency" hypothesis and matches the failure being specific to theopencodefree tier (request-shape gate).Cross-posting the control observation and the zero-logging source findings to #58176 so they're in the canonical thread. Happy for this issue to be closed as a duplicate.
neriousy commentedon Oct 23, 2026
Closing as a duplicate of #58176. The control-arm and logging evidence from this report has already been cross-posted there, so let’s keep the investigation in that canonical issue.
opencode-agent commentedon Oct 24, 2026
We haven't heard back in a day, so I'm closing this as a duplicate of #58176. That issue has been reproduced on 2.1.3. The cause is that the free tier rejects the title request with
403 FreeTierError, and the error is then dropped without being logged. Your suggested fallback to the first prompt as the title is in the open PR #57624. Please follow #58176 for updates, and add any new findings there. If your problem turns out to be different, reply here and we can reopen.