Summary: Clicking "Delete" in a workspace's settings shows an error toast "Failed to delete artist link" (bottom-right) and the workspace is not deleted. Artist deletion works fine.
Steps to reproduce
- Open settings for a workspace (repro account:
1e6c40e0-fdc6-4b69-856e-17d7b86d44a3).
- Click the Delete button.
- Toast appears (bottom-right): "Failed to delete artist link".
Expected vs actual
- Expected: the workspace is deleted (no error).
- Actual: error toast; the workspace remains.
Root cause
The workspace Delete reuses the artist delete flow, but a workspace's owner link lives in a different table.
- chat:
components/ArtistSetting/DeleteModal.tsx:12-20 → hooks/useDeleteArtist.ts:32 → lib/artists/deleteArtist.ts:14-26 issues DELETE {API}/api/artists/{id}. On failure it throws new Error(data.error || …) (deleteArtist.ts:25), so the toast text is the api's error string (which is why "Failed to delete artist link" doesn't appear anywhere in the chat repo).
- api:
app/api/artists/[id]/route.ts → lib/artists/deleteArtistHandler.ts → lib/artists/deleteArtist.ts:26-29:
const deletedLinks = await deleteAccountArtistId(requesterAccountId, artistId);
if (!deletedLinks.length) {
throw new Error("Failed to delete artist link");
}
deleteAccountArtistId deletes from account_artist_ids (lib/supabase/account_artist_ids/deleteAccountArtistId.ts:18-30). Workspaces store their owner link in a different table, account_workspace_ids (written at creation — lib/workspaces/createWorkspaceInDb.ts:40), so the delete matches 0 rows and throws. The access guard passes earlier via the org-share path (lib/artists/checkAccountArtistAccess.ts:36-49), so it isn't blocked before reaching the failing delete.
Data model: both artists and workspaces are accounts rows; the distinguishing relationship is which join table holds membership — account_artist_ids (artist) vs account_workspace_ids (workspace). The delete endpoint hard-codes the artist table.
Proposed fix
Preferred — workspace-aware delete: add DELETE /api/workspaces/{id} that deletes from account_workspace_ids (new deleteAccountWorkspaceId(requester, workspaceId) under lib/supabase/account_workspace_ids/), plus cleanup of the accounts / account_info / artist_organization_ids rows on last-owner removal; then branch the chat delete on isWorkspace (the create flow already tags workspaces — CreateWorkspaceModal.tsx:59-62) to call a deleteWorkspace client fn.
Smaller-blast alternative: make api/lib/artists/deleteArtist.ts fall back to deleting the account_workspace_ids row before throwing; only error if neither table matched. Cleaner long-term is the dedicated endpoint (codebase keeps account/artist/workspace distinct).
Done when
- Deleting a workspace removes it with no error toast.
- Deleting an artist still works.
Suspected code
- chat:
components/ArtistSetting/DeleteModal.tsx:12-20, hooks/useDeleteArtist.ts:32,36, lib/artists/deleteArtist.ts:14-26
- api:
app/api/artists/[id]/route.ts, lib/artists/deleteArtist.ts:26-29 (throws here), lib/supabase/account_artist_ids/deleteAccountArtistId.ts:18-30, lib/artists/checkAccountArtistAccess.ts:36-49, lib/workspaces/createWorkspaceInDb.ts:40, lib/supabase/account_workspace_ids/
Filed in chat per house rule even though most of the fix lands in api — links out by full ref.
Found while testing chat#1793 (artist Connectors tab).
🤖 Generated with Claude Code
Summary: Clicking "Delete" in a workspace's settings shows an error toast "Failed to delete artist link" (bottom-right) and the workspace is not deleted. Artist deletion works fine.
Steps to reproduce
1e6c40e0-fdc6-4b69-856e-17d7b86d44a3).Expected vs actual
Root cause
The workspace Delete reuses the artist delete flow, but a workspace's owner link lives in a different table.
components/ArtistSetting/DeleteModal.tsx:12-20→hooks/useDeleteArtist.ts:32→lib/artists/deleteArtist.ts:14-26issuesDELETE {API}/api/artists/{id}. On failure it throwsnew Error(data.error || …)(deleteArtist.ts:25), so the toast text is the api'serrorstring (which is why "Failed to delete artist link" doesn't appear anywhere in the chat repo).app/api/artists/[id]/route.ts→lib/artists/deleteArtistHandler.ts→lib/artists/deleteArtist.ts:26-29:deleteAccountArtistIddeletes fromaccount_artist_ids(lib/supabase/account_artist_ids/deleteAccountArtistId.ts:18-30). Workspaces store their owner link in a different table,account_workspace_ids(written at creation —lib/workspaces/createWorkspaceInDb.ts:40), so the delete matches 0 rows and throws. The access guard passes earlier via the org-share path (lib/artists/checkAccountArtistAccess.ts:36-49), so it isn't blocked before reaching the failing delete.Data model: both artists and workspaces are
accountsrows; the distinguishing relationship is which join table holds membership —account_artist_ids(artist) vsaccount_workspace_ids(workspace). The delete endpoint hard-codes the artist table.Proposed fix
Preferred — workspace-aware delete: add
DELETE /api/workspaces/{id}that deletes fromaccount_workspace_ids(newdeleteAccountWorkspaceId(requester, workspaceId)underlib/supabase/account_workspace_ids/), plus cleanup of theaccounts/account_info/artist_organization_idsrows on last-owner removal; then branch the chat delete onisWorkspace(the create flow already tags workspaces —CreateWorkspaceModal.tsx:59-62) to call adeleteWorkspaceclient fn.Smaller-blast alternative: make
api/lib/artists/deleteArtist.tsfall back to deleting theaccount_workspace_idsrow before throwing; only error if neither table matched. Cleaner long-term is the dedicated endpoint (codebase keeps account/artist/workspace distinct).Done when
Suspected code
components/ArtistSetting/DeleteModal.tsx:12-20,hooks/useDeleteArtist.ts:32,36,lib/artists/deleteArtist.ts:14-26app/api/artists/[id]/route.ts,lib/artists/deleteArtist.ts:26-29(throws here),lib/supabase/account_artist_ids/deleteAccountArtistId.ts:18-30,lib/artists/checkAccountArtistAccess.ts:36-49,lib/workspaces/createWorkspaceInDb.ts:40,lib/supabase/account_workspace_ids/Found while testing chat#1793 (artist Connectors tab).
🤖 Generated with Claude Code