wavetermdev/waveterm · warning
block not found: %q
Error message
block not found: %q
What it means
Inside deleteBlockObj, if the block row does not exist (DBGet returns nil, nil) the transaction aborts with "block not found: %q". Unlike error 1296 this is a missing-object condition, not a storage failure. Note DeleteBlock normally guards nil blocks first, so this fires when the block vanishes between the outer check and the transaction (a race), or when deleteBlockObj is invoked directly.
Source
Thrown at pkg/wcore/block.go:205
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)
}
if block == nil {
return -1, fmt.Errorf("block not found: %q", blockId)
}
if len(block.SubBlockIds) > 0 {
return -1, fmt.Errorf("block has subblocks, must delete subblocks first")
}
parentORef := waveobj.ParseORefNoErr(block.ParentORef)
parentBlockCount := -1
if parentORef != nil {
if parentORef.OType == waveobj.OType_Tab {
tab, _ := wstore.DBGet[*waveobj.Tab](tx.Context(), parentORef.OID)
if tab != nil {
tab.BlockIds = utilfn.RemoveElemFromSlice(tab.BlockIds, blockId)
wstore.DBUpdate(tx.Context(), tab)
parentBlockCount = len(tab.BlockIds)
}
} else if parentORef.OType == waveobj.OType_Block {
parentBlock, _ := wstore.DBGet[*waveobj.Block](tx.Context(), parentORef.OID)
if parentBlock != nil {
parentBlock.SubBlockIds = utilfn.RemoveElemFromSlice(parentBlock.SubBlockIds, blockId)View on GitHub (pinned to a4447c1563)
Solutions
- Treat it as success/idempotent — the block is already gone; ignore or log it.
- Deduplicate delete requests client-side (skip if the block is no longer in state).
- Retry-safe: catch this message and return nil from the calling command.
- Verify the block id being passed is correct and current (re-fetch block list first).
Example fix
// before
if err := wclient.DeleteBlock(ctx, blockId, false); err != nil {
return err // fails on double-delete
}
// after
if err := wclient.DeleteBlock(ctx, blockId, false); err != nil && !strings.Contains(err.Error(), "block not found") {
return err
}
return nil // already deleted: OK Defensive patterns
Strategy: type-guard
Validate before calling
block, _ := wstore.DBGet[*waveobj.Block](ctx, blockId)
if block == nil {
return nil // nothing to delete; skip the call entirely
}
wcore.DeleteBlock(ctx, blockId, false) Type guard
func blockExists(ctx context.Context, blockId string) bool {
b, err := wstore.DBGet[*waveobj.Block](ctx, blockId)
return err == nil && b != nil
} Try / catch
if err := wcore.DeleteBlock(ctx, blockId, false); err != nil {
if strings.Contains(err.Error(), "block not found") {
return nil // idempotent success
}
return err
} Prevention
- Treat block-not-found on delete as success (idempotent deletes).
- Remove the block from client state immediately when issuing the delete to avoid double-submits.
- Disable/delete buttons once a delete is in flight.
When it happens
Trigger: Block deleted concurrently after DeleteBlock's initial DBGet but before deleteBlockObj's transaction reads it; calling deleteBlockObj with a nonexistent/typo'd block id; retrying a delete that already succeeded.
Common situations: Double-click delete causing two rapid DeleteBlock calls; multiple windows deleting the same block; replayed RPC commands after reconnect.
Related errors
- error getting block: %w
- error deleting subblock %s: %w
- error deleting block: %w
- block has subblocks, must delete subblocks first
- window ${windowId} not found
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/b674094f5aeae12a.
Report an issue: GitHub.