wavetermdev/waveterm · error
error finding workspace for tab to delete %s: %w
Error message
error finding workspace for tab to delete %s: %w
What it means
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.
Source
Thrown at pkg/wcore/block.go:185
err := DeleteBlock(ctx, subBlockId, recursive)
if err != nil {
return fmt.Errorf("error deleting subblock %s: %w", subBlockId, err)
}
}
}
parentBlockCount, err := deleteBlockObj(ctx, blockId)
if err != nil {
return fmt.Errorf("error deleting block: %w", err)
}
log.Printf("DeleteBlock: parentBlockCount: %d", parentBlockCount)
parentORef := waveobj.ParseORefNoErr(block.ParentORef)
if recursive && parentORef.OType == waveobj.OType_Tab && parentBlockCount == 0 {
// if parent tab has no blocks, delete the tab
log.Printf("DeleteBlock: parent tab has no blocks, deleting tab %s", parentORef.OID)
parentWorkspaceId, err := wstore.DBFindWorkspaceForTabId(ctx, parentORef.OID)
if err != nil {
return fmt.Errorf("error finding workspace for tab to delete %s: %w", parentORef.OID, err)
}
newActiveTabId, err := DeleteTab(ctx, parentWorkspaceId, parentORef.OID, true)
if err != nil {
return fmt.Errorf("error deleting tab %s: %w", parentORef.OID, err)
}
SendActiveTabUpdate(ctx, parentWorkspaceId, newActiveTabId)
}
sendBlockCloseEvent(blockId)
return nil
}
// returns the updated block count for the parent object
func deleteBlockObj(ctx context.Context, blockId string) (int, error) {
return wstore.WithTxRtn(ctx, func(tx *wstore.TxWrap) (int, error) {
block, err := wstore.DBGet[*waveobj.Block](tx.Context(), blockId)
if err != nil {
return -1, fmt.Errorf("error getting block: %w", err)
}View on GitHub (pinned to a4447c1563)
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.
Example fix
// before
wcore.DeleteBlock(ctx, blockId, true) // fails when tab's workspace row is gone
// after
wsId, err := wstore.DBFindWorkspaceForTabId(ctx, tabId)
if err != nil {
// repair or skip tab cascade
return wcore.DeleteBlock(ctx, blockId, false)
}
wcore.DeleteBlock(ctx, blockId, true) Defensive patterns
Strategy: fallback
Validate before calling
wsId, err := wstore.DBFindWorkspaceForTabId(ctx, tabId)
if err != nil {
// fall back to non-recursive delete
return wcore.DeleteBlock(ctx, blockId, false)
} Try / catch
if err := wcore.DeleteBlock(ctx, blockId, true); err != nil && strings.Contains(err.Error(), "error finding workspace for tab") {
// degrade gracefully: block deletion matters more than tab cleanup
log.Printf("skipping tab cascade: %v", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Orphaned tab rows after a partial workspace deletion or corrupted store; DB read error during the workspace->tab join lookup.
Related errors
- error deleting tab %s: %w
- error getting block: %w
- error deleting subblock %s: %w
- error deleting block: %w
- unable to get layout id for given tab id %s: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/d2a7fc809898414d.
Report an issue: GitHub.