{"record":{"id":"17d980cc6bfdfaa9","repo":"wavetermdev/waveterm","slug":"error-deleting-workspace-w","errorCode":null,"errorMessage":"error deleting workspace: %w","messagePattern":"error deleting workspace: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/workspaceservice/workspaceservice.go","lineNumber":101,"sourceCode":"\treturn ws, nil\n}\n\nfunc (svc *WorkspaceService) DeleteWorkspace_Meta() tsgenmeta.MethodMeta {\n\treturn tsgenmeta.MethodMeta{\n\t\tArgNames: []string{\"workspaceId\"},\n\t}\n}\n\nfunc (svc *WorkspaceService) DeleteWorkspace(workspaceId string) (waveobj.UpdatesRtnType, string, error) {\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()\n\tctx = waveobj.ContextWithUpdates(ctx)\n\tdeleted, claimableWorkspace, err := wcore.DeleteWorkspace(ctx, workspaceId, true)\n\tif claimableWorkspace != \"\" {\n\t\treturn nil, claimableWorkspace, nil\n\t}\n\tif err != nil {\n\t\treturn nil, claimableWorkspace, fmt.Errorf(\"error deleting workspace: %w\", err)\n\t}\n\tif !deleted {\n\t\treturn nil, claimableWorkspace, nil\n\t}\n\tupdates := waveobj.ContextGetUpdatesRtn(ctx)\n\tgo func() {\n\t\tdefer func() {\n\t\t\tpanichandler.PanicHandler(\"WorkspaceService:DeleteWorkspace:SendUpdateEvents\", recover())\n\t\t}()\n\t\twps.Broker.SendUpdateEvents(updates)\n\t}()\n\treturn updates, claimableWorkspace, nil\n}\n\nfunc (svc *WorkspaceService) ListWorkspaces() (waveobj.WorkspaceList, error) {\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()\n\treturn wcore.ListWorkspaces(ctx)","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/workspaceservice/workspaceservice.go#L83-L119","documentation":"WorkspaceService.DeleteWorkspace deletes a workspace via wcore.DeleteWorkspace(ctx, workspaceId, true) and wraps failures with this error — unless the workspace has claimable windows, in which case the claimable id is returned instead (no error). The wrapped error typically means the workspace id was not found or the deletion/persistence step failed.","triggerScenarios":"DeleteWorkspace called with a nonexistent or already-deleted workspaceId, or wcore's deletion (object removal, update recording) fails due to DB error or timeout; concurrent deletion from another client.","commonSituations":"Double-click/double-submit of a delete action deleting the same workspace twice; frontend workspace list stale after another window deleted the workspace; DB failure mid-deletion leaving partial state; scripts iterating a cached list of workspace ids.","solutions":["Handle the claimableWorkspace return value first — the call may legitimately return no error and no deletion when windows must be claimed elsewhere","Unwrap the %w error: for not-found, refresh the workspace list and treat the workspace as already deleted; for DB errors, retry once after checking DB health","Guard UI delete actions against duplicate submissions (disable after first click / dedupe by id in flight)","Re-fetch workspaces after any failed delete before retrying with the same id"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const exists = await WorkspaceService.GetWorkspace(workspaceId).catch(() => null);\nif (!exists) throw new Error(`workspace ${workspaceId} already deleted`);","typeGuard":"function isDeletableWorkspace(ws: waveobj.Workspace | null | undefined, id: string): ws is waveobj.Workspace {\n  return ws != null && ws.OID === id;\n}","tryCatchPattern":"claimable, cw, err := WorkspaceService.DeleteWorkspace(ctx, workspaceId)\nif err != nil {\n    if strings.Contains(err.Error(), \"not found\") { return refreshWorkspaces() }\n    return fmt.Errorf(\"delete workspace: %w\", err)\n}\nif claimable == nil && cw != \"\" { /* windows need claiming first; surface to user */ }","preventionTips":["Handle the claimableWorkspace return value (windows must be re-homed) before assuming deletion failed","Deduplicate delete submissions so the same id is never deleted twice concurrently","Refresh the workspace list after any delete attempt, success or failure","Process bulk deletions against a freshly-fetched id list, not a cached one"],"tags":["workspace","delete","not-found"],"backgroundTag":"waveobj-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}