{"record":{"id":"6ab7c00e7f577889","repo":"wavetermdev/waveterm","slug":"error-setting-active-tab-w","errorCode":null,"errorMessage":"error setting active tab: %w","messagePattern":"error setting active tab: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/workspaceservice/workspaceservice.go","lineNumber":179,"sourceCode":"\t\t}()\n\t\twps.Broker.SendUpdateEvents(updates)\n\t}()\n\treturn tabId, updates, nil\n}\n\nfunc (svc *WorkspaceService) SetActiveTab_Meta() tsgenmeta.MethodMeta {\n\treturn tsgenmeta.MethodMeta{\n\t\tArgNames: []string{\"workspaceId\", \"tabId\"},\n\t}\n}\n\nfunc (svc *WorkspaceService) SetActiveTab(workspaceId string, tabId string) (waveobj.UpdatesRtnType, error) {\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()\n\tctx = waveobj.ContextWithUpdates(ctx)\n\terr := wcore.SetActiveTab(ctx, workspaceId, tabId)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error setting active tab: %w\", err)\n\t}\n\t// check all blocks in tab and start controllers (if necessary)\n\ttab, err := wstore.DBMustGet[*waveobj.Tab](ctx, tabId)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting tab: %w\", err)\n\t}\n\tblockORefs := tab.GetBlockORefs()\n\tblocks, err := wstore.DBSelectORefs(ctx, blockORefs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting tab blocks: %w\", err)\n\t}\n\tupdates := waveobj.ContextGetUpdatesRtn(ctx)\n\tgo func() {\n\t\tdefer func() {\n\t\t\tpanichandler.PanicHandler(\"WorkspaceService:SetActiveTab:SendUpdateEvents\", recover())\n\t\t}()\n\t\twps.Broker.SendUpdateEvents(updates)\n\t}()","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/workspaceservice/workspaceservice.go#L161-L197","documentation":"SetActiveTab changes the workspace's active tab and returns update events. If wcore.SetActiveTab fails (workspace or tab not found, DB error, timeout), the error is wrapped as \"error setting active tab: %w\". It indicates the tab switch could not be persisted before any controllers are started.","triggerScenarios":"Calling SetActiveTab(workspaceId, tabId) with a tabId that does not belong to the given workspace, a nonexistent workspaceId, or a DB/timeout failure inside wcore.SetActiveTab.","commonSituations":"Frontend holding a stale tabId after the tab was closed elsewhere; race between closing a tab and switching to it; corrupted workspace state.","solutions":["Verify the tabId exists in the workspace before calling SetActiveTab","Unwrap the error to see whether wcore.SetActiveTab reported a not-found vs DB failure","Refresh the client's view of the workspace to clear stale tab ids","Check DB health and DefaultTimeout headroom"],"exampleFix":"// before\nwsSvc.SetActiveTab(workspaceId, possiblyStaleTabId)\n// after\ntab, err := wstore.DBGet[*waveobj.Tab](ctx, possiblyStaleTabId)\nif err != nil { return fmt.Errorf(\"tab no longer exists: %w\", err) }\nwsSvc.SetActiveTab(workspaceId, tab.OID)","handlingStrategy":"validation","validationCode":"ws, err := wstore.DBGet[*waveobj.Workspace](ctx, workspaceId)\nif err != nil { return err }\nif !slices.Contains(ws.TabIds, tabId) {\n    return fmt.Errorf(\"tab %s not in workspace %s\", tabId, workspaceId)\n}\n_, err = svc.SetActiveTab(workspaceId, tabId)","typeGuard":null,"tryCatchPattern":"_, err := svc.SetActiveTab(workspaceId, tabId)\nif err != nil {\n    if errors.Is(err, waveobj.ErrNotFound) { /* reload workspace state */ }\n    return err\n}","preventionTips":["Confirm tabId belongs to the target workspace before activation","Handle tab-deleted events promptly in the UI","Avoid calling SetActiveTab concurrently with CloseTab on the same tab"],"tags":["go","workspace","tab","rpc"],"backgroundTag":"wrapped-error-propagation","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}