CL-6495: say what actually failed when a workbench can't be created - #227
Conversation
Pins the wording describeWorkbenchCreateFailure should pick for each shape of cause: a precondition Error shown verbatim, an ApiQueryError routed through describeApiError, and a status-less/network failure still landing on the generic try-again.
The create-workbench catch bound nothing, so whatever createWorkbenchFromTemplate threw was discarded and every failure showed the same 'try again' toast regardless of whether retrying could help. Now the cause is logged with its status/path so the next occurrence names which step fired, and the toast copy is honest: a precondition failure (no setup agent, an unavailable template) shows its own message instead of a retry prompt that would be a lie, and an ApiQueryError runs through describeApiError so the status drives the wording, matching the treatment other pages already use.
|
Peer review: items 2-4 hold (tests/tsc/lint green, toast-styling gap confirmed real and upstream-only), but item 1 (raw-Error-verbatim safety) does not hold — found a live leak, not a hypothetical one. Blocking merge until fixed. The leak
if (cause instanceof Error && !(cause instanceof ApiQueryError)) {
return cause.message;
}But
Two more plain-
Net effect: for these steps, a failure now shows the person an internal path/tenant id or a schema-validation dump instead of the old generic "try again" — worse than the bug being fixed, even though the two curated precondition throws in Secondary: logged
|
The previous fix denylisted ApiQueryError before showing an Error's message verbatim, which failed open: ChatApiError (thrown by createWorkbench, patchWorkbenchSettings, and the GitHub-connect steps) slipped straight through and put raw request paths and schema summaries in the toast — the exact leak class this ticket exists to close. Same for plain Errors from listPluginsForTenant and instantiateWorkbenchTemplate. Inverted to an allow-list: only WorkbenchPreconditionError (a new marker for the two intentionally user-facing precondition messages — no setup agent, an unavailable template) is shown verbatim. ApiQueryError and ChatApiError each go through their own describer (describeApiError, describeChatError, the latter now exported from chat-ui), and anything else falls to one generic message. A future error type therefore fails safe by default instead of leaking. Also reads status off ChatApiError for the create-failure log, since four of the five awaited steps throw that type and previously logged status: undefined regardless of what actually failed.
The stub serves an empty definitions list, so the create fails its precondition rather than the request. The generic toast used to hide that; now that preconditions are shown verbatim, the assertion names the failure the test actually exercises.
Summary
new-workbench-picker.tsx's create-workbench catch bound nothing:Whatever
createWorkbenchFromTemplatethrew was discarded, so everyfailure looked identical and there was no signal to debug the owner's
intermittent repro from.
getLogger("web.new-workbench-picker"))with its message, and
status/pathwhen it's anApiQueryError—pathalone names which step in
createWorkbenchFromTemplatefired (manifestread vs. block deploy vs.
POST /chat/workbenches, etc.), so the nextoccurrence should identify the failing step immediately.
describeWorkbenchCreateFailureshows aprecondition
Error's message verbatim (e.g. "A code-review workbenchisn't available here yet.") instead of flattening it into a lying
"try again," and runs anything else through
describeApiError— thesame treatment
global-routines.ts,home-page.tsx, andlibrary-page.tsxalready use for this class of failure.Toast system finding (priority 2)
Confirmed there is exactly one toast system:
@corbits/react-ui'stoast(message: string)re-export, used by every call site in the repo.But at the pinned SHA (
3b12281), that function has no error/destructivevariant at all — it always renders the same neutral, unstyled treatment
regardless of content. The "doesn't match the design system" complaint
isn't a misuse of the toast system in this repo; it's a capability gap
in
corbitsdev/react-uiitself (notoast.error/destructive stylingexists to opt into). Not fixed here per "core UI lives in react-ui" —
flagging for a follow-up there.
Underlying-failure candidates (priority 3)
Traced
createWorkbenchFromTemplate's awaits for what could produce theowner's intermittent failure, now nameable via the logged
path:fetchWorkbenchTemplateManifest(GET .../library/templates/:id) —CL-6458 made library seeding lazy-on-read; a first-read race before the
shelf has converged is plausible and returns
null→ the "isn'tavailable here yet" precondition Error.
deployWorkbenchTemplateBlock(POST .../template-blocks/:asset/deploy)— the block-workflow deploy step.
createWorkbench(POST .../chat/workbenches) andpatchWorkbenchSettings— the mint + pending-connections write.listAgentDefinitions/findMyraDefinition— a bench with no defaultsetup agent throws the same class of precondition Error.
getConnectGithubState,startReviewingGithubRepos) only runs when GitHub is already connected.Could not reproduce the intermittent case in this pass, but the next
occurrence's logged
pathshould say which of these it was.Sibling sweep
Grepped
apps/web/srcandpackages/*/srcfor other barecatch {blocks. 87 matches — most are legitimate best-effort fallbacks
(localStorage/sessionStorage reads/writes, JSON.parse defaults). A
smaller cluster mirrors this exact bug's class (user action → generic
toast, real error discarded):
shell/workbench-list.tsx:271,shell/context-menu/items.tsx:54,connect-service-actions.ts:122,chat-ui/timeline.tsx:784,chat-ui/use-thread-navigation.ts:128,chat-ui/composer.tsx:559,settings-ui/account-section.tsx:98. Notfixed here — worth its own ticket.
Test plan
bun test ./src/pages/new-workbench-picker.test.ts— new unittests for
describeWorkbenchCreateFailurebun test ./test/new-workbench-picker.test.tsx— existing DOMsuite still green
bunx tsc --noEmit -p apps/webbun run lintfrom repo rootDoes not touch layout (CL-6489 owns that in this same file).
Fixes CL-6495