pingdotgg / pingdotgg/t3code

[Bug]: Thread title and branch-name generation fail silently when the text generation provider is unhealthy

Open
#5,359 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
23k
Forks
5.9k
Avg merge
11h 14m
Merged PRs (30d)
357

Description

Before submitting
  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.
Area

apps/server

Steps to reproduce
  1. Have both Codex and Claude enabled as providers. Leave Settings → Text generation model untouched, i.e. on its default (instanceId: "codex", gpt-5.6-luna).
  2. Make the Codex CLI unusable without disabling the provider — e.g. corrupt ~/.codex/config.toml so the app-server refuses to load it. In my case a concurrent write left a duplicate table + an orphaned key, and the provider probe recorded:
    "status": "error",
    "message": "Codex app-server provider probe failed: failed to reload config: ~/.codex/config.toml:7:1: duplicate key."
    
  3. Start a new thread with any first message.
  4. Observe the thread title and, for worktree threads, the generated branch name.
  5. Right-click the thread → Regenerate title.
Expected behavior

Either:

  • text generation falls back to a provider that is actually usable (Claude was status: "ready" and authenticated the whole time), or
  • the failure is surfaced the way generateCommitMessage surfaces it (Text generation failed in generateCommitMessage: …, see #5182) — a toast or a thread-activity entry.
Actual behavior

Nothing happens, and nothing tells you why.

  • Thread titles permanently stay as the raw titleSeed (the first message text), so the feature looks like it is simply not implemented.
  • Worktree branch names permanently stay as the t3code-<hash> fallback — all 20 of my worktrees are t3code-09b397af, t3code-0a41d30a, …
  • Regenerate title clears the pending state and writes no title. In my event store: a client thread.meta-updated with "regenerateTitle": true at 12:24:03.721Z, then a server thread.meta-updated with "titleRegeneration": null at 12:24:08.553Z and no title. No error anywhere in the UI.
  • Meanwhile commit-message generation through the same broken provider does show an error, so the app is inconsistent about the same underlying failure.

Two things combine to make this silent:

  1. No health-based fallback. resolveTextGenerationProviderisModelSelectionProviderEnabled only falls back when the instance is enabled: false. An instance that is enabled but whose probe is in status: "error" stays selected forever. (resolveSourceControlWriterModelSelection right next to it does consult isProviderAvailable, so the helper already exists.) The fallbackTextGenerationProvider path also only scans the legacy settings.providers map, which is empty on an instance-based config, so even a disabled provider would not have produced a fallback here.
  2. The failure is swallowed. Both maybeGenerateThreadTitleForFirstTurn and maybeGenerateAndRenameWorktreeBranchForFirstTurn end in Effect.catchCause(cause => Effect.logWarning(...)). It never reaches the client — no toast, no thread.activity-appended.

Related, but not the same report: #5182 (closed) is the "why is Codex the default text generation provider when I don't use Codex" half of this. This issue is about what happens after that default silently stops working.

Impact

Minor bug or occasional failure

Version or commit

0.0.31

Environment

Linux (CachyOS), t3code 0.0.31 desktop, Codex CLI 0.146.0, Claude Code 2.1.221 (Claude Max), providers: codex (enabled, status: "error") + claudeAgent (enabled, status: "ready")

Logs or stack traces
# ~/.t3/caches/codex.json
{
  "displayName": "Codex",
  "enabled": true,
  "installed": true,
  "status": "error",
  "message": "Codex app-server provider probe failed: failed to reload config: ~/.codex/config.toml:7:1: duplicate key.",
  "checkedAt": "2026-08-04T20:47:11.045Z"
}

# ~/.t3/caches/claudeAgent.json — healthy the entire time
{
  "displayName": "Claude",
  "status": "ready",
  "auth": { "status": "authenticated", "type": "Claude Max" },
  "checkedAt": "2026-08-04T20:47:12.652Z"
}

# state.sqlite — every title write in ~3 months of history came from `client`
# (manual renames) or `provider` (the "New session - <ts>" mirror).
# Not one `server` actor title write:
sqlite> SELECT occurred_at, actor_kind, payload_json FROM orchestration_events
        WHERE event_type='thread.meta-updated' AND payload_json LIKE '%title%'
        ORDER BY sequence DESC LIMIT 3;
2026-07-31T12:24:08.553Z|server|{"threadId":"…","titleRegeneration":null,"updatedAt":"…"}
2026-07-31T12:24:03.721Z|client|{"threadId":"…","regenerateTitle":true,"previousTitle":"i need to update some info in stores, ignore that …","titleRegeneration":…}
2026-07-28T16:23:37.784Z|client|{"threadId":"…","title":"Pusher Security","updatedAt":"…"}
Workaround

Set Settings → Text generation model to a provider that works (Claude → Haiku 4.5). Titles and branch names start generating immediately. But you have to already suspect the setting exists — nothing in the product points you at it, because the failure is never surfaced.

Suggested fix
  • Have resolveTextGenerationProvider consider provider availability/health, not just enabled, and make fallbackTextGenerationProvider scan providerInstances rather than only the legacy providers map.
  • On title / branch-name generation failure, append a thread.activity-appended entry (or reuse the Text generation failed in <operation> surfacing that commit-message generation already has) instead of only Effect.logWarning.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Trace resolveTextGenerationProvider, isModelSelectionProviderEnabled, and fallbackTextGenerationProvider for instance selection and health checks. Then inspect maybeGenerateThreadTitleForFirstTurn and maybeGenerateAndRenameWorktreeBranchForFirstTurn alongside generateCommitMessage and issue #5182. Done means an unhealthy selected provider falls back when possible, and title or branch-generation failures reach the user through an activity entry, toast, or equivalent error.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
56/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.