fix: avoid 500 when generating chat title from rename dialog and remove unused endpoint - #28306
Conversation
Clicking Generate in the rename dialog (or Regenerate) runs manual chat
title generation under an internal deadline. When the model call times
out, the error ("context deadline exceeded") bubbled up to the propose
and regenerate handlers and fell through to a raw 500 that leaked the
wrapped error chain.
Translate context.DeadlineExceeded to 504 with a friendly retry message
and context.Canceled to 499 (client closed request) in both the
propose-title and regenerate-title handlers, matching by errors.Is so
the wrapped deadline error is detected. Genuine, unrelated failures keep
their existing 500 surface.
Generated by Coder Agents.
@ethanndickson please let me know if you think going all the way to the small model enhancement is the move here and I can keep going. I'm just defaulting to a minimal change first given release timing. |
|
My understanding is just very slow model responses, most likely because it's using a big expensive model with high effort. I think it's still possible to hit in that scenario since this does not include any logic to select a smaller model if possible. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 90d6322cb3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…tion Manual chat title generation (rename dialog Generate and Regenerate) previously ran a single model under a 30s deadline. A slow provider hit the deadline and failed the request, which the handler now surfaces as a 504. Walk the enabled preferred short-text models the user has credentials for, then the chat's own model, bounded by an overall 90s budget with a 30s per-attempt deadline. Fall through to the next candidate only on per-attempt timeout or chatretry-classified transient errors; stop on non-retryable errors (auth, config) so real failures still surface. When the context is canceled after a candidate has already failed, the walker surfaces ctx.Err() instead of the stale candidate error, so the handler maps caller cancellation to 499 and overall-budget expiry to 504 rather than a stale 500. Fallback models resolve lazily so a run that succeeds on the first candidate never constructs the others. Replaces the single-model resolveManualTitleModel (and the now-unused selectPreferredConfiguredShortTextModelConfig) with resolveManualTitleCandidates. Generated by Coder Agents.
…te-title-500 # Conflicts: # coderd/x/chatd/chatd.go # coderd/x/chatd/quickgen.go # coderd/x/chatd/quickgen_internal_test.go # coderd/x/chatd/title_override_internal_test.go
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 74c7c78842
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…llback Address two review findings: - Map manual title errors to 504 only when a title deadline actually expired, via the chatd.ErrManualTitleTimedOut sentinel, so provider failures that merely wrap a transport deadline keep the 500 surface. - Append the chat's own model as the final walk candidate when preferred short-text models exist, so the walk can still succeed when every preferred candidate fails. It skips itself when it duplicates an already-attempted preferred config.
The frontend only uses POST /chats/{chat}/title/propose (rename dialog);
nothing calls /title/regenerate anymore. Remove the endpoint, its
codersdk client method, the chatd persist/broadcast path it alone used
(persistManualTitle, regenerateChatTitleWithStore), and its tests. Port
the paste-only-chat coverage to the propose suite and add the missing
swagger annotations for the propose endpoint so it appears in the API
reference.
Docs previewCheck off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here. |
…ation Restore the single-model manual title path (resolveManualTitleModel and selectPreferredConfiguredShortTextModelConfig) and delete the candidate walk (titlewalk.go). Keep the 30s generation deadline and the ErrManualTitleTimedOut sentinel so the handler still maps genuine title timeouts to a friendly 504 and caller cancellation to 499. Generated by Coder Agents.
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
I've increased the scope of this PR to include removing the unused and redundant endpoint discussed in the Linear issue attached slack thread. Adding @jaaydenh for a safety and sanity check on this |
Problem
Clicking Generate in the Rename Chat dialog runs manual chat-title
generation. It runs a single model under a 30s deadline; a slow provider hit
the deadline and returned
context deadline exceeded, which bubbled up wrappedto the
propose-titlehandler and fell through to a raw 500 that leakedthe wrapped chain in
detail:{"message":"Failed to generate chat title.", "detail":"generate manual title: generate structured title: tool-based generation failed: context deadline exceeded"}Fixes CODAGT-278.
Change
Two parts:
1. Friendly error mapping (
coderd/exp_chats.go)Translate manual-title pipeline errors instead of returning a raw 500, matching
with
errors.Isso the deeply-wrapped errors are detected:The 504 branch keys off the
chatd.ErrManualTitleTimedOutsentinel, whichchatd attaches only when the title-generation deadline actually expired, so a
provider failure that merely wraps an unrelated transport deadline keeps its
500 surface.
context.Canceled→ 499, and only when the request context itself iscanceled, so a provider error wrapping
context.Canceled(e.g. an upstream401) on a live request is not misreported as a client-closed request.
Genuine, unrelated failures keep their existing 500 surface, and the translated
copy does not leak the raw error
detail. No frontend change is required: therename dialog already renders the API
message.The generation path itself is unchanged: a single model (deployment override,
else the preferred short-text model, else the chat's own model) under the
existing 30s deadline.
2. Remove the redundant
/title/regenerateendpointThe frontend only calls
POST /chats/{chat}/title/propose(rename dialog);nothing calls
/title/regenerateanymore, and both funneled into the samegeneration path since #24820. Removed the route, handler, codersdk client
method, and the persist/broadcast path only it used (
persistManualTitle,regenerateChatTitleWithStore). Ported the paste-only-chat coverage to thepropose suite and added the missing swagger annotations for the propose
endpoint so it now appears in the API reference.
Tests
TestMaybeWriteManualTitleTimeoutErr: 504 for the tagged title timeout,499 only with a canceled request context, and fall-through preserving the
500 for untagged deadline wraps, live-context cancels, and unrelated errors.
TestProposeChatTitle(10 subtests), including the paste-only-chat coverageported from the removed regenerate suite.
Notes for reviewers
Prior art: PR #25424 (Dean, reviewed by Ethan + Codex; closed, never merged)
The earlier #25424 approached this by walking multiple models with fallback.
A multi-model candidate walk was prototyped on this branch and then removed to
keep the change minimal: this PR only maps errors to friendly statuses and
deletes the redundant endpoint, leaving the single-model generation path as it
is on
main.Generated by Coder Agents on behalf of @f0ssel.