{"record":{"id":"33ce1cb7a0bdea5d","repo":"wavetermdev/waveterm","slug":"tab-not-found-q","errorCode":null,"errorMessage":"tab not found: %q","messagePattern":"tab not found: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wcore/block.go","lineNumber":137,"sourceCode":"\tdefer cancelFn()\n\ttelemetry.UpdateActivity(tctx, wshrpc.ActivityUpdate{\n\t\tRenderers: map[string]int{blockView: 1},\n\t})\n\ttelemetry.RecordTEvent(tctx, &telemetrydata.TEvent{\n\t\tEvent: \"action:createblock\",\n\t\tProps: telemetrydata.TEventProps{\n\t\t\tBlockView:       blockView,\n\t\t\tBlockController: blockController,\n\t\t\tBlockSubBlock:   subBlock,\n\t\t},\n\t})\n}\n\nfunc createBlockObj(ctx context.Context, tabId string, blockDef *waveobj.BlockDef, rtOpts *waveobj.RuntimeOpts) (*waveobj.Block, error) {\n\treturn wstore.WithTxRtn(ctx, func(tx *wstore.TxWrap) (*waveobj.Block, error) {\n\t\ttab, _ := wstore.DBGet[*waveobj.Tab](tx.Context(), tabId)\n\t\tif tab == nil {\n\t\t\treturn nil, fmt.Errorf(\"tab not found: %q\", tabId)\n\t\t}\n\t\tblockId := uuid.NewString()\n\t\tblockData := &waveobj.Block{\n\t\t\tOID:         blockId,\n\t\t\tParentORef:  waveobj.MakeORef(waveobj.OType_Tab, tabId).String(),\n\t\t\tRuntimeOpts: rtOpts,\n\t\t\tMeta:        blockDef.Meta,\n\t\t}\n\t\twstore.DBInsert(tx.Context(), blockData)\n\t\ttab.BlockIds = append(tab.BlockIds, blockId)\n\t\twstore.DBUpdate(tx.Context(), tab)\n\t\treturn blockData, nil\n\t})\n}\n\n// Must delete all blocks individually first.\n// Also deletes LayoutState.\n// recursive: if true, will recursively close parent tab, window, workspace, if they are empty.","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wcore/block.go#L119-L155","documentation":"createBlockObj wraps all block creation in a write transaction. Before inserting the new Block it loads the parent Tab by tabId; if no Tab row exists for that id it aborts the transaction with \"tab not found\". The library throws this to enforce referential integrity — a Block must always hang off an existing Tab via its ParentORef.","triggerScenarios":"Calling CreateBlock (or any path that reaches createBlockObj) with a tabId that does not exist in the wstore DB — e.g. a stale/deleted tab id, a mistyped id, or a tab id from a different workspace.","commonSituations":"Frontend holding a cached tab id after the tab was closed or the tab was deleted by a recursive DeleteBlock; passing a workspace or window id where a tab id is expected; racing tab deletion with block creation.","solutions":["Verify the tab id exists before creating the block (wstore.DBGet[*waveobj.Tab] or an RPC tab lookup).","Refresh the tab list and use the current active tab id instead of a cached one.","Check that the tab was not deleted concurrently (e.g. by DeleteBlock with recursive=true removing empty tabs).","Confirm you are passing the tab OID, not a workspace/window/layout id."],"exampleFix":"// before\nblock, _ := wclient.CreateBlock(ctx, staleTabId, blockDef, opts) // panics/errors\n// after\ntab, _ := wstore.DBGet[*waveobj.Tab](ctx, tabId)\nif tab == nil {\n    tabId, _ = wclient.CreateTab(ctx, workspaceId)\n}\nblock, err := wclient.CreateBlock(ctx, tabId, blockDef, opts)","handlingStrategy":"validation","validationCode":"tab, _ := wstore.DBGet[*waveobj.Tab](ctx, tabId)\nif tab == nil {\n    return fmt.Errorf(\"cannot create block: tab %s does not exist\", tabId)\n}","typeGuard":"func tabExists(ctx context.Context, tabId string) bool {\n    tab, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)\n    return err == nil && tab != nil\n}","tryCatchPattern":null,"preventionTips":["Always resolve tab ids from a fresh tab-list query, never long-lived caches.","Validate the id's OType is Tab before use (waveobj.ParseORef).","Handle tab-deleted events to invalidate stale tab references in UI state."],"tags":["wave-terminal","block-creation","missing-tab","referential-integrity"],"backgroundTag":"referenced-object-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}