{"record":{"id":"d2a7fc809898414d","repo":"wavetermdev/waveterm","slug":"error-finding-workspace-for-tab-to-delete-s-w","errorCode":null,"errorMessage":"error finding workspace for tab to delete %s: %w","messagePattern":"error finding workspace for tab to delete (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wcore/block.go","lineNumber":185,"sourceCode":"\t\t\terr := DeleteBlock(ctx, subBlockId, recursive)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting subblock %s: %w\", subBlockId, err)\n\t\t\t}\n\t\t}\n\t}\n\tparentBlockCount, err := deleteBlockObj(ctx, blockId)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error deleting block: %w\", err)\n\t}\n\tlog.Printf(\"DeleteBlock: parentBlockCount: %d\", parentBlockCount)\n\tparentORef := waveobj.ParseORefNoErr(block.ParentORef)\n\n\tif recursive && parentORef.OType == waveobj.OType_Tab && parentBlockCount == 0 {\n\t\t// if parent tab has no blocks, delete the tab\n\t\tlog.Printf(\"DeleteBlock: parent tab has no blocks, deleting tab %s\", parentORef.OID)\n\t\tparentWorkspaceId, err := wstore.DBFindWorkspaceForTabId(ctx, parentORef.OID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error finding workspace for tab to delete %s: %w\", parentORef.OID, err)\n\t\t}\n\t\tnewActiveTabId, err := DeleteTab(ctx, parentWorkspaceId, parentORef.OID, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error deleting tab %s: %w\", parentORef.OID, err)\n\t\t}\n\t\tSendActiveTabUpdate(ctx, parentWorkspaceId, newActiveTabId)\n\t}\n\tsendBlockCloseEvent(blockId)\n\treturn nil\n}\n\n// returns the updated block count for the parent object\nfunc deleteBlockObj(ctx context.Context, blockId string) (int, error) {\n\treturn wstore.WithTxRtn(ctx, func(tx *wstore.TxWrap) (int, error) {\n\t\tblock, err := wstore.DBGet[*waveobj.Block](tx.Context(), blockId)\n\t\tif err != nil {\n\t\t\treturn -1, fmt.Errorf(\"error getting block: %w\", err)\n\t\t}","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wcore/block.go#L167-L203","documentation":"When recursive=true and the block's parent tab becomes empty, DeleteBlock tries to close the tab too. It first resolves the owning workspace with DBFindWorkspaceForTabId; if that lookup fails it wraps it as \"error finding workspace for tab to delete %s: %w\". The tab cascade cannot proceed without the workspace id needed by DeleteTab.","triggerScenarios":"Recursive delete of the last block in a tab, but DBFindWorkspaceForTabId returns an error — the tab's workspace linkage is missing from the store or the DB query itself fails.","commonSituations":"Orphaned tab rows after a partial workspace deletion or corrupted store; DB read error during the workspace->tab join lookup.","solutions":["Inspect the wrapped cause; if it is a DB error, fix the store/IO issue first.","Verify the tab actually belongs to a workspace (check its ParentORef); delete orphaned tabs manually.","Skip the recursive cascade (recursive=false) and delete the empty tab through a separate code path once the workspace mapping is repaired.","Rebuild workspace-tab relationships from block/tab ParentORef data if the index is inconsistent."],"exampleFix":"// before\nwcore.DeleteBlock(ctx, blockId, true) // fails when tab's workspace row is gone\n// after\nwsId, err := wstore.DBFindWorkspaceForTabId(ctx, tabId)\nif err != nil {\n    // repair or skip tab cascade\n    return wcore.DeleteBlock(ctx, blockId, false)\n}\nwcore.DeleteBlock(ctx, blockId, true)","handlingStrategy":"fallback","validationCode":"wsId, err := wstore.DBFindWorkspaceForTabId(ctx, tabId)\nif err != nil {\n    // fall back to non-recursive delete\n    return wcore.DeleteBlock(ctx, blockId, false)\n}","typeGuard":null,"tryCatchPattern":"if err := wcore.DeleteBlock(ctx, blockId, true); err != nil && strings.Contains(err.Error(), \"error finding workspace for tab\") {\n    // degrade gracefully: block deletion matters more than tab cleanup\n    log.Printf(\"skipping tab cascade: %v\", err)\n}","preventionTips":["Keep workspace-tab relationships intact; repair orphaned tabs proactively.","Fall back to recursive=false when the workspace mapping cannot be resolved.","Clean up empty tabs with a separate periodic job instead of relying solely on cascades."],"tags":["wave-terminal","tab-deletion","workspace-lookup","cascade-delete","wrapped-error"],"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"}