fix: solve #5852 — chat pane FK violation inserting chat_sessions.v2_workspace_id for local-first workspaces
Root cause
chat.createSession (packages/trpc/src/router/chat/chat.ts) inserted chat_sessions.v2_workspace_id directly from the client-supplied input.v2WorkspaceId. That column has an FK to cloud v2_workspaces (chat_sessions_v2_workspace_id_v2_workspaces_id_fk).
Post local-first migration, v2 workspaces are authored in host.db and the electric-synced cloud v2_workspaces table can be empty for the org (0 rows) while the desktop runs several local workspaces. The FK can therefore never be satisfied: the insert throws and the raw DrizzleQueryError surfaces in the chat pane on every message. The older REST route (apps/api/src/app/api/chat/[sessionId]/route.ts) already has a retry-without-workspaceId fallback for this exact failure class; the tRPC path had none.
The fix
Before inserting, verify the workspace exists cloud-side and only pin v2_workspace_id when it does; otherwise persist NULL — mirroring the REST route's shouldRetryWithoutWorkspaceId behavior (option (a) from the issue).
The check is done up front inside the transaction rather than as catch-and-retry, because a failed INSERT aborts the surrounding Postgres transaction (current transaction is aborted…), which would make an in-transaction retry fail regardless. A SELECT returning zero rows leaves the transaction usable.
Tests
Added packages/trpc/src/router/chat/chat.test.ts:
- reproduction — with the cloud
v2_workspacesset empty (local-first), the mock insert faithfully models the FK and throws the reported error. Before the fixcreateSessionrejected with the raw SQL; after the fix it falls back tov2_workspace_id = NULLand returns the session id. - regression guard — when the workspace does exist cloud-side, its id is preserved.
Both pass; packages/trpc typechecks and lints clean.
Note: the issue also suggests catching this in ChatPane to show a human-readable message instead of raw SQL. That is left out of this scoped fix since the FK violation no longer occurs on the happy path; it can be a follow-up for defense-in-depth.
Closes #5852
Summary by cubic
Prevent FK violations when creating chat sessions by verifying v2_workspace_id against cloud v2_workspaces and inserting NULL when missing. Fixes chat pane errors for local-first workspaces and aligns tRPC with the REST fallback (closes #5852).
- Bug Fixes
- In
packages/trpc/src/router/chat/chat.ts, check for the workspace inv2Workspacesinside the transaction; only setv2_workspace_idwhen it exists, else persistNULL. - Avoid catch-and-retry since a failed insert aborts the transaction; use a pre-insert
SELECTinstead. - Added
packages/trpc/src/router/chat/chat.test.tscovering local-first fallback and cloud-present cases.
- In