wavetermdev/waveterm · error
error deleting block: %w
Error message
error deleting block: %w
What it means
After subblocks are cleared, DeleteBlock calls deleteBlockObj to remove the block row and compute the parent's remaining block count. If that transaction fails, the error is wrapped as "error deleting block: %w". This is the core record-deletion step for the block itself.
Source
Thrown at pkg/wcore/block.go:175
func DeleteBlock(ctx context.Context, blockId string, recursive bool) error {
block, err := wstore.DBGet[*waveobj.Block](ctx, blockId)
if err != nil {
return fmt.Errorf("error getting block: %w", err)
}
if block == nil {
return nil
}
if len(block.SubBlockIds) > 0 {
for _, subBlockId := range block.SubBlockIds {
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)View on GitHub (pinned to a4447c1563)
Solutions
- Delete all subblocks first (pass recursive=true to DeleteBlock).
- Read the wrapped cause to determine whether the DB read or the parent update failed.
- Retry after fixing the store state; missing blocks short-circuit earlier, so retries are safe.
- Check that no concurrent operation re-added subblocks between checks.
Example fix
// before wclient.DeleteBlock(ctx, parentId, false) // subblocks remain -> fails // after wclient.DeleteBlock(ctx, parentId, true) // subblocks deleted before the parent
Defensive patterns
Strategy: try-catch
Validate before calling
block, _ := wstore.DBGet[*waveobj.Block](ctx, blockId) ready := block != nil && len(block.SubBlockIds) == 0
Try / catch
if err := wcore.DeleteBlock(ctx, blockId, true); err != nil {
if strings.Contains(err.Error(), "error deleting block") {
log.Printf("core delete failed: %v", err)
}
return err
} Prevention
- Delete via the public DeleteBlock (recursive), not deleteBlockObj directly.
- Ensure subblocks are cleared before any non-recursive delete.
- Monitor wrapped causes for transaction/store health issues.
When it happens
Trigger: deleteBlockObj returns an error: DBGet of the block fails, the block is unexpectedly nil, the block still has subblocks, or the parent lookup/update inside the transaction fails.
Common situations: Calling DeleteBlock on a parent without recursive=true while subblocks remain (though the wrapper usually surfaces the "subblocks first" message); transaction failure from store corruption or concurrent modification.
Related errors
- error getting block: %w
- error deleting subblock %s: %w
- error finding workspace for tab to delete %s: %w
- error deleting tab %s: %w
- block not found: %q
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/e548b077654b2822.
Report an issue: GitHub.