{"record":{"id":"08a469f44210ac15","repo":"wavetermdev/waveterm","slug":"error-getting-tab-w","errorCode":null,"errorMessage":"error getting tab: %w","messagePattern":"error getting tab: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/clientservice/clientservice.go","lineNumber":37,"sourceCode":")\n\ntype ClientService struct{}\n\nconst DefaultTimeout = 2 * time.Second\n\nfunc (cs *ClientService) GetClientData() (*waveobj.Client, error) {\n\tlog.Println(\"GetClientData\")\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()\n\treturn wcore.GetClientData(ctx)\n}\n\nfunc (cs *ClientService) GetTab(tabId string) (*waveobj.Tab, error) {\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()\n\ttab, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting tab: %w\", err)\n\t}\n\treturn tab, nil\n}\n\nfunc (cs *ClientService) GetAllConnStatus(ctx context.Context) ([]wshrpc.ConnStatus, error) {\n\tsshStatuses := conncontroller.GetAllConnStatus()\n\twslStatuses := wslconn.GetAllConnStatus()\n\treturn append(sshStatuses, wslStatuses...), nil\n}\n\n// moves the window to the front of the windowId stack\nfunc (cs *ClientService) FocusWindow(ctx context.Context, windowId string) error {\n\treturn wcore.FocusWindow(ctx, windowId)\n}\n\nfunc (cs *ClientService) AgreeTos(ctx context.Context) (waveobj.UpdatesRtnType, error) {\n\tctx = waveobj.ContextWithUpdates(ctx)\n\tclientData, err := wstore.DBGetSingleton[*waveobj.Client](ctx)","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/clientservice/clientservice.go#L19-L55","documentation":"GetTab wraps any failure from wstore.DBGet[*waveobj.Tab] with 'error getting tab: %w'. It is thrown when the tab lookup in the wstore database fails — most often because no Tab object exists for the given tabId, or the underlying DB read errored. The wrapped error is preserved so callers can inspect the root cause (e.g. 'key not found').","triggerScenarios":"Calling ClientService.GetTab with a tabId that was deleted, a typo'd/stale tabId from a cached reference, or when the wstore DB read fails (IO/corruption).","commonSituations":"Frontend holds a tabId after the tab was closed in another window; restoring workspace state referencing removed tabs; passing a blockId or windowId instead of a tabId.","solutions":["Verify the tabId exists (check it came from a current window/tab list, not a stale cache)","Check the wrapped error: if 'key not found', treat the tab as deleted and refresh the tab list","If DB errors persist, inspect the wstore DB file for corruption/permissions"],"exampleFix":"// before\ntab, err := cs.GetTab(staleTabId)\n// after\ntab, err := cs.GetTab(tabId)\nif err != nil && strings.Contains(err.Error(), \"key not found\") {\n    tab, err = cs.GetTab(currentTabId) // re-resolve from active window\n}","handlingStrategy":"try-catch","validationCode":"if tabId == \"\" { return fmt.Errorf(\"tabId required\") }","typeGuard":"func hasTabId(tabId string) bool { return strings.TrimSpace(tabId) != \"\" }","tryCatchPattern":"tab, err := cs.GetTab(tabId)\nif err != nil {\n    if strings.Contains(err.Error(), \"key not found\") { /* tab deleted; refresh list */ }\n    return err\n}","preventionTips":["Obtain tabIds from live tab listings, never long-lived caches","Distinguish tabId from blockId/windowId at call sites","Treat 'key not found' as an expected outcome and handle idempotently"],"tags":["go","database","wstore","tab"],"backgroundTag":"record-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}